<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>analytics &amp;mdash; Цифровой дворник</title>
    <link>https://articles.clr58.ru/tag:analytics</link>
    <description>Практические заметки о сетях, self-hosting, виртуализации, мониторинге, автоматизации и локальном ИИ.</description>
    <pubDate>Wed, 30 Sep 2026 01:15:14 +0000</pubDate>
    <item>
      <title>Почему Umami не видит ботов, а логи видят всех</title>
      <link>https://articles.clr58.ru/umami-goaccess</link>
      <description>&lt;![CDATA[Обложка&#xA;&#xA;Заходишь в свою веб-аналитику, а там тишина. За сутки — горстка просмотров и пара посетителей. Вроде сайт живой, статьи публикуются, кто-то их читает. Но панель упорно показывает, что кроме тебя и пары друзей никто не заходит.&#xA;&#xA;Знакомо? У меня так было с блогом. Пока я не полез в access-логи веб-сервера и не обнаружил, что на сайт ходят толпы ботов, а аналитика их просто не видит. Дальше — почему так вышло и что я с этим сделал.&#xA;&#xA;Как Umami считает визиты&#xA;&#xA;Umami (и почти любая JS-аналитика) работает через скрипт на странице:&#xA;&#xA;&lt;script async src=&#34;https://analytics.example/script.js&#34;&#xA;        data-website-id=&#34;...&#34;  /script&#xA;&#xA;Логика простая: браузер загружает страницу → выполняет скрипт → скрипт шлёт событие на api/send. Всё считает клиент, на стороне сервера — только приём.&#xA;&#xA;И вот тут первая ловушка: боты не исполняют JavaScript. Поисковики, AI-краулеры, SEO-сканеры скачивают HTML и уходят. Они не запускают скрипт аналитики, поэтому для Umami их просто не существует.&#xA;&#xA;Вторая ловушка: Umami по умолчанию фильтрует ботов по User-Agent. Даже если какой-то краулер решит выполнить скрипт, встроенная детекция ботов его отсеет. То есть панель намеренно показывает только «настоящих» людей.&#xA;&#xA;Звучит разумно, пока тебе не нужно понять: а кто вообще стучится в мой сайт?&#xA;&#xA;Что я увидел в логах&#xA;&#xA;Когда я сравнил картину из Umami и из access-логов Caddy, разница оказалась смешной.&#xA;&#xA;Umami за сутки: около полусотни просмотров, двадцать с лишним посетителей.&#xA;&#xA;А в логах веб-сервера за тот же день — толпа. Вот кто приходил:&#xA;&#xA;AhrefsBot — SEO-краулер&#xA;GPTBot, ChatGPT-User — краулеры OpenAI&#xA;ClaudeBot — Anthropic&#xA;PerplexityBot — Perplexity&#xA;Googlebot, Yandex, Bing — поисковики&#xA;TelegramBot — превью ссылок в мессенджере&#xA;плюс всякая мелочь вроде сканеров уязвимостей&#xA;&#xA;Суммарно — под сотню обращений в день. И ни одного из них в Umami.&#xA;&#xA;Вывод простой: JS-аналитика считает людей, а не трафик. Если хочешь видеть всех — надо смотреть логи сервера.&#xA;&#xA;GoAccess вместо панели&#xA;&#xA;GoAccess — это терминальный (и не только) анализатор логов, который гоняет access-лог и выдаёт отчёт: кто, откуда, сколько, какие страницы, какие статусы, какие боты. Никакого JS — только то, что реально дошло до сервера.&#xA;&#xA;Ставится элементарно:&#xA;&#xA;apt install goaccess&#xA;&#xA;Но есть нюанс. Caddy по умолчанию пишет логи в stderr, а не в файл. Чтобы GoAccess их увидел, нужен файл:&#xA;&#xA;log {&#xA;    output file /var/log/caddy/access.log&#xA;}&#xA;&#xA;Тут я наступил на граблю: Caddy в systemd крутится под ProtectSystem=full, и файл лога вне разрешённых путей он создать не может — падает с «permission denied». Лечится drop-in&#39;ом:&#xA;&#xA;/etc/systemd/system/caddy.service.d/rw-logs.conf&#xA;[Service]&#xA;ReadWritePaths=/var/log/caddy&#xA;&#xA;Потом systemctl daemon-reload &amp;&amp; systemctl reload caddy.&#xA;&#xA;JSON-логи Caddy — не для GoAccess&#xA;&#xA;Вторая засада: Caddy пишет логи в JSON, а GoAccess ест классический Combined Log Format. Приходится конвертировать. Я сделал это через jq:&#xA;&#xA;jq -r &#39;select(.request != null)&#xA;  | select((.request.headers&#34;User-Agent&#34; // &#34;&#34;) | test(&#34;Uptime-Kuma|curl/|Python-urllib&#34;; &#34;i&#34;) | not)&#xA;  | &#34;\(.request.clientip // .request.remoteip) - - \(.ts|strftime(&#34;%d/%b/%Y:%H:%M:%S %z&#34;))] \&#34;\(.request.method) \(.request.uri) \(.request.proto)\&#34; \(.status) \(.size // 0) \&#34;\(.request.headers.Referer[0] // &#34;-&#34;)\&#34; \&#34;\(.request.headers[&#34;User-Agent&#34; // &#34;-&#34;)\&#34;&#34;&#39; \&#xA;  access.log   access.clf&#xA;&#xA;Заметили фильтр? Я отсекаю собственный мониторинг (Uptime-Kuma долбит сайт каждые 30 секунд — за сутки это тысячи строк шума) и свои же curl-запросы. Иначе отчёт превращается в статистику «сколько раз мой мониторинг пинговал самого себя».&#xA;&#xA;Дальше — рендер:&#xA;&#xA;goaccess --log-format=&#39;%h %^[%d:%t %^] &#34;%r&#34; %s %b &#34;%R&#34; &#34;%u&#34;&#39; \&#xA;  --date-format=&#39;%d/%b/%Y&#39; --time-format=&#39;%H:%M:%S&#39; \&#xA;  -f access.clf -o /var/www/logs/index.html --no-global-config&#xA;&#xA;Обновляю отчёт по cron раз в пять минут. Финальный штрих — отдаю HTML через Caddy на поддомен logs.example, закрытый тем же allow-list&#39;ом, что и админки (снаружи пускаю только свои IP).&#xA;&#xA;Что в итоге&#xA;&#xA;Теперь у меня два инструмента, и каждый на своём месте:&#xA;&#xA;Umami — чтобы видеть живых людей: что читают, откуда пришли, что держится на странице. Тут чистота важнее полноты.&#xA;GoAccess по логам — чтобы видеть весь трафик: людей, ботов, сканеры, статусы 404 и 500, откуда реально ломятся.&#xA;&#xA;Один не заменяет другой. Панель аналитики молчит про ботов не потому, что их нет, а потому что она про них не должна знать. А логи не знают про поведение человека на странице, зато честно показывают каждый запрос.&#xA;&#xA;Мораль: если кажется, что «на сайт никто не заходит» — проверьте логи, прежде чем расстраиваться. Возможно, там как раз наоборот — заходят, и ещё как.&#xA;&#xA;---&#xA;&#xA;А у вас чем смотрите трафик? Только панель, или логи тоже смотрите?&#xA;&#xA;#selfhosting #analytics #monitoring #network #goaccess #umami&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://paste.clr58.ru/post-umami-goaccess-digclean.jpg" alt="Обложка"></p>

<p>Заходишь в свою веб-аналитику, а там тишина. За сутки — горстка просмотров и пара посетителей. Вроде сайт живой, статьи публикуются, кто-то их читает. Но панель упорно показывает, что кроме тебя и пары друзей никто не заходит.</p>

<p>Знакомо? У меня так было с блогом. Пока я не полез в access-логи веб-сервера и не обнаружил, что на сайт <strong>ходят толпы ботов</strong>, а аналитика их просто не видит. Дальше — почему так вышло и что я с этим сделал.</p>

<h2 id="как-umami-считает-визиты">Как Umami считает визиты</h2>

<p>Umami (и почти любая JS-аналитика) работает через скрипт на странице:</p>

<pre><code class="language-html">&lt;script async src=&#34;https://analytics.example/script.js&#34;
        data-website-id=&#34;...&#34;&gt;&lt;/script&gt;
</code></pre>

<p>Логика простая: браузер загружает страницу → выполняет скрипт → скрипт шлёт событие на <code>api/send</code>. Всё считает клиент, на стороне сервера — только приём.</p>

<p>И вот тут первая ловушка: <strong>боты не исполняют JavaScript</strong>. Поисковики, AI-краулеры, SEO-сканеры скачивают HTML и уходят. Они не запускают скрипт аналитики, поэтому для Umami их просто не существует.</p>

<p>Вторая ловушка: <strong>Umami по умолчанию фильтрует ботов</strong> по User-Agent. Даже если какой-то краулер решит выполнить скрипт, встроенная детекция ботов его отсеет. То есть панель намеренно показывает только «настоящих» людей.</p>

<p>Звучит разумно, пока тебе не нужно понять: а кто вообще стучится в мой сайт?</p>

<h2 id="что-я-увидел-в-логах">Что я увидел в логах</h2>

<p>Когда я сравнил картину из Umami и из access-логов Caddy, разница оказалась смешной.</p>

<p>Umami за сутки: <strong>около полусотни просмотров, двадцать с лишним посетителей</strong>.</p>

<p>А в логах веб-сервера за тот же день — толпа. Вот кто приходил:</p>
<ul><li>AhrefsBot — SEO-краулер</li>
<li>GPTBot, ChatGPT-User — краулеры OpenAI</li>
<li>ClaudeBot — Anthropic</li>
<li>PerplexityBot — Perplexity</li>
<li>Googlebot, Yandex, Bing — поисковики</li>
<li>TelegramBot — превью ссылок в мессенджере</li>
<li>плюс всякая мелочь вроде сканеров уязвимостей</li></ul>

<p>Суммарно — под сотню обращений в день. И ни одного из них в Umami.</p>

<p>Вывод простой: <strong>JS-аналитика считает людей, а не трафик.</strong> Если хочешь видеть всех — надо смотреть логи сервера.</p>

<h2 id="goaccess-вместо-панели">GoAccess вместо панели</h2>

<p>GoAccess — это терминальный (и не только) анализатор логов, который гоняет access-лог и выдаёт отчёт: кто, откуда, сколько, какие страницы, какие статусы, какие боты. Никакого JS — только то, что реально дошло до сервера.</p>

<p>Ставится элементарно:</p>

<pre><code class="language-bash">apt install goaccess
</code></pre>

<p>Но есть нюанс. Caddy по умолчанию пишет логи в stderr, а не в файл. Чтобы GoAccess их увидел, нужен файл:</p>

<pre><code class="language-caddy">log {
    output file /var/log/caddy/access.log
}
</code></pre>

<p>Тут я наступил на граблю: Caddy в systemd крутится под <code>ProtectSystem=full</code>, и файл лога вне разрешённых путей он создать не может — падает с «permission denied». Лечится drop-in&#39;ом:</p>

<pre><code class="language-ini"># /etc/systemd/system/caddy.service.d/rw-logs.conf
[Service]
ReadWritePaths=/var/log/caddy
</code></pre>

<p>Потом <code>systemctl daemon-reload &amp;&amp; systemctl reload caddy</code>.</p>

<h2 id="json-логи-caddy-не-для-goaccess">JSON-логи Caddy — не для GoAccess</h2>

<p>Вторая засада: Caddy пишет логи в JSON, а GoAccess ест классический Combined Log Format. Приходится конвертировать. Я сделал это через jq:</p>

<pre><code class="language-bash">jq -r &#39;select(.request != null)
  | select((.request.headers[&#34;User-Agent&#34;][0] // &#34;&#34;) | test(&#34;Uptime-Kuma|curl/|Python-urllib&#34;; &#34;i&#34;) | not)
  | &#34;\(.request.client_ip // .request.remote_ip) - - [\(.ts|strftime(&#34;%d/%b/%Y:%H:%M:%S %z&#34;))] \&#34;\(.request.method) \(.request.uri) \(.request.proto)\&#34; \(.status) \(.size // 0) \&#34;\(.request.headers.Referer[0] // &#34;-&#34;)\&#34; \&#34;\(.request.headers[&#34;User-Agent&#34;][0] // &#34;-&#34;)\&#34;&#34;&#39; \
  access.log &gt; access.clf
</code></pre>

<p>Заметили фильтр? Я отсекаю собственный мониторинг (Uptime-Kuma долбит сайт каждые 30 секунд — за сутки это тысячи строк шума) и свои же curl-запросы. Иначе отчёт превращается в статистику «сколько раз мой мониторинг пинговал самого себя».</p>

<p>Дальше — рендер:</p>

<pre><code class="language-bash">goaccess --log-format=&#39;%h %^[%d:%t %^] &#34;%r&#34; %s %b &#34;%R&#34; &#34;%u&#34;&#39; \
  --date-format=&#39;%d/%b/%Y&#39; --time-format=&#39;%H:%M:%S&#39; \
  -f access.clf -o /var/www/logs/index.html --no-global-config
</code></pre>

<p>Обновляю отчёт по cron раз в пять минут. Финальный штрих — отдаю HTML через Caddy на поддомен <code>logs.example</code>, закрытый тем же allow-list&#39;ом, что и админки (снаружи пускаю только свои IP).</p>

<h2 id="что-в-итоге">Что в итоге</h2>

<p>Теперь у меня два инструмента, и каждый на своём месте:</p>
<ul><li><strong>Umami</strong> — чтобы видеть живых людей: что читают, откуда пришли, что держится на странице. Тут чистота важнее полноты.</li>
<li><strong>GoAccess по логам</strong> — чтобы видеть весь трафик: людей, ботов, сканеры, статусы 404 и 500, откуда реально ломятся.</li></ul>

<p>Один не заменяет другой. Панель аналитики молчит про ботов не потому, что их нет, а потому что она про них не должна знать. А логи не знают про поведение человека на странице, зато честно показывают каждый запрос.</p>

<p>Мораль: если кажется, что «на сайт никто не заходит» — проверьте логи, прежде чем расстраиваться. Возможно, там как раз наоборот — заходят, и ещё как.</p>

<hr>

<p>А у вас чем смотрите трафик? Только панель, или логи тоже смотрите?</p>

<p><a href="https://articles.clr58.ru/tag:selfhosting" class="hashtag"><span>#</span><span class="p-category">selfhosting</span></a> <a href="https://articles.clr58.ru/tag:analytics" class="hashtag"><span>#</span><span class="p-category">analytics</span></a> <a href="https://articles.clr58.ru/tag:monitoring" class="hashtag"><span>#</span><span class="p-category">monitoring</span></a> <a href="https://articles.clr58.ru/tag:network" class="hashtag"><span>#</span><span class="p-category">network</span></a> <a href="https://articles.clr58.ru/tag:goaccess" class="hashtag"><span>#</span><span class="p-category">goaccess</span></a> <a href="https://articles.clr58.ru/tag:umami" class="hashtag"><span>#</span><span class="p-category">umami</span></a></p>
]]></content:encoded>
      <guid>https://articles.clr58.ru/umami-goaccess</guid>
      <pubDate>Fri, 28 Aug 2026 20:09:38 +0000</pubDate>
    </item>
  </channel>
</rss>