Талисман NordBastion — белый медведь — стоит за резной кафедрой из скандинавского камня; над ним парит большой голографический дашборд циан-цвета с гистограммами, растущим линейным графиком и кольцевой диаграммой с одним акцентом янтарного цвета, а единый непрерывный поток светящихся точек цвета циан тянется от арочного окна, освещённого северным сиянием, через дашборд к покрытой рунами двери хранилища, позади которой видна серверная стойка
Инструкция · Аналитика·18 мин на чтение · 40 мин практики

Вы установили один script, чтобы наблюдать за своими читателями.
Он наблюдает в ответ и отчитывается в другое место.

Аналитика — последний сторонний тег, который многие до сих пор оставляют, и именно он видит всё: каждую страницу, каждого читателя, каждый час, на системе, которая вам не принадлежит и которую вы не можете проверить. Шесть шагов, чтобы заменить её собственным счётчиком — Umami, Plausible Community Edition, Matomo или вообще ничем, кроме журнала сервера — работающим на Nordic-машине, арендованной без документа, удостоверяющего личность. Без cookie по умолчанию, без баннера, о котором нужно спорить, без передачи вашей аудитории в третью страну. От $3.90 в месяц. Проверено на Debian 12.

Шесть шагов
  1. 01

    Выбор

    Четыре инструмента, одна честная таблица

  2. 02

    Провизионирование

    Один поддомен, три порта

  3. 03

    Развернуть

    Compose, Caddy, первый вход

  4. 04

    Инструментирование

    Один тег и путь через свой домен

  5. 05

    Соответствие

    Два закона, а не один

  6. 06

    Keep

    Сроки хранения, резервные копии, забытый журнал

Перед началом · Что такое тег

Это не счётчик. Это строка в отчёте.

Считать посетителей — дело по-настоящему полезное, и в желании это делать нет ничего предосудительного. Вам нужно знать, помогла ли переработка страницы, какую статью люди действительно дочитывают до конца, какой источник перехода присылает читателей, а не отказы, и не сломал ли вчерашний деплой незаметно оформление заказа в одном из браузеров. На каждый из этих вопросов отвечает таблица просмотров страниц, и каждый из них — законная причина для измерений.

На что стоит посмотреть прямо — это на ту схему, которую почти все приняли, чтобы получить эти ответы. Стандартный тег аналитики — это фрагмент кода, написанный рекламной компанией, который вы размещаете на каждой странице своего сайта и указываете ему выполняться в браузере вашего читателя. Он считывает адрес страницы, источник перехода, экран, язык, устройство; устанавливает или считывает идентификатор на устройстве; отправляет всё это в систему, которую вы не можете проверить, в стране, чьи правила вы не выбирали; и передаёт получившийся файл компании, чья прибыль строится на знании того, что делают люди. Владелец сайта получает дашборд. Дашборд — это меньшая половина этой сделки.

Счёт приходит в четыре части, и очевидна из них только одна. Есть баннер согласия, который существует практически исключительно из-за этого одного тега, который стоит вам заметной доли посетителей прямо на входе, и за управление которым вы затем платите ещё одному поставщику. Есть вопрос передачи данных, потому что данные ваших читателей уходят в третью страну, и кому-то в итоге приходится письменно объяснять, почему это законно. Есть сами данные — это ваша читательская аудитория, в базе данных, к которой у вас нет доступа иначе как через предложенные вам отчёты. И есть зависимость: продукт снимают с поддержки, переименовывают или перестраивают по чужому графику, а в прошлый раз, когда это случилось, вместе с ним пропали и старые измерения.

Самостоятельный хостинг убирает все четыре проблемы сразу, и это не большая работа. Программное обеспечение зрелое, бесплатное и скучное; машина стоит несколько долларов в месяц; работы — на один вечер. В обмен вы получаете таблицу, которая принадлежит вам, на оборудовании в выбранной вами юрисдикции, без третьей стороны, которую нужно раскрывать, и — при большинстве конфигураций — без баннера, о котором нужно спорить. Четыре способа узнать, сколько человек читает ваш сайт, и сколько стоит каждый из них:

Свойство Большой бесплатный тег аналитики SaaS-аналитика с приоритетом приватности То же самое ПО, ваш VPS
У кого хранится таблица с данными о читателяхРекламная компанияПоставщик, по договоруВы, на диске
Нужен баннер согласияДа, на практике всегдаОбычно нетОбычно нет — см. шаг 05
Данные покидают ЕЭЗДа, по замыслуЗависит от поставщикаТолько если вы выберете машину за пределами ЕЭЗ
Третьи стороны, которые нужно раскрыватьКак минимум один, плюс его субобработчикиОдин обработчикНет
Блокируется списками фильтровСильноЧасто — по имени хостаРедко, если запрос идёт с собственного домена
Необработанные данные доступны вамНет — только отчётыЧерез API, пока вы платитеЭто ваша база данных
Ежемесячная стоимость при 100k просмотровВ деньгах — ничегоДесятки долларов, растёт с трафиком$3.90–$7.90, фиксированно
Выбирайте, когдаВам нужна интеграция с рекламной платформой, и вы принимаете всё остальноеВам нужна этичность без необходимости что-либо запускать самостоятельноЧитательская аудитория — ваша, и таблица с данными — тоже

Третий столбец — это настоящий ответ, а не соломенное чучело: хостинговый поставщик, ориентированный на приватность, снимает большинство тех же проблем для людей, которым не стоит держать собственные серверы, и платить такому поставщику — лучший исход, чем оставить рекламный тег. Это руководство — для случая, когда вы уже арендуете машину или собирались это сделать.

Шаг 01 · Выбор

Четыре инструмента. Счёт определяет база данных.

Эти четыре варианта — не четыре вариации одного и того же. Они отличаются тем, во что они сохраняют данные, и именно этот единственный выбор определяет объём потребляемой памяти, рост диска, риск при обновлении и глубину отчётов. Сначала читайте столбец о хранилище, и только потом — столбец о функциях; именно в таком порядке решение и принимается на самом деле.

Инструмент Стек и хранилище Разумный тариф Выбирайте для
UmamiNode-приложение + PostgreSQL или MySQL. Два контейнера.Sentinel · $3.90Ответ по умолчанию. Лёгкий, понятный, без cookie, мультисайтовый, под лицензией MIT.
Plausible Community EditionElixir-приложение + PostgreSQL + ClickHouse. Четыре контейнера.Garrison · $7.90Цели, воронки и публичные дашборды; быстрые запросы при больших объёмах.
MatomoPHP-приложение + MariaDB, плюс задача архивирования по расписанию.Garrison · $7.90Функциональный паритет с прежним решением — сегменты, когорты, электронная коммерция, импорт журналов.
GoAccessОдин бинарник, читающий журнал доступа веб-сервера. Без базы данных.Тот, что вы уже используетеСовсем без JavaScript — статичные сайты, документация, API.

Umami — вариант, к которому стоит обращаться, если только у вас нет причин поступить иначе. Это Node-приложение, работающее с единой реляционной базой данных, ему достаточно одного гигабайта памяти, схема состоит из нескольких таблиц, которые можно опросить самостоятельно, а отчёты показывают именно то, ради чего большинство людей открывают дашборд: страницы, источники переходов, страны, устройства, а при необходимости — и пользовательские события. По умолчанию он не использует cookie, и для этого не нужно ничего настраивать.

Plausible Community Edition — версия для самостоятельного размещения того же облачного продукта, и дополнительный элемент здесь — ClickHouse, колоночная база данных, которая делает агрегирующие запросы по десяткам миллионов строк почти мгновенными и при этом использует ровно столько памяти, сколько вы ей позволите. Это честный обмен, если у вас несколько миллионов просмотров в месяц, и странный — если меньше. Прочитайте условия лицензии проекта перед развёртыванием: эта версия предназначена для ведения собственной аналитики, а не для перепродажи в виде услуги.

Matomo — единственный из четырёх инструментов, который по-настоящему заменяет прежнее решение функция за функцией, и у этой честной формулировки есть оборотная сторона: вы получаете сегменты, воронки, когорты, атрибуцию для электронной коммерции, тепловые карты через плагины и возможность импортировать собственные серверные журналы, а вместе с этим — большое PHP-приложение, чьи исходные таблицы быстро растут и чьи отчёты заранее вычисляются задачей архивирования, которую нужно планировать самостоятельно. Присмотреться к нему стоит в любом случае по двум причинам: его можно настроить так, чтобы он не устанавливал cookie, а конфигурации для измерения аудитории на его основе появлялись в опубликованных регуляторами перечнях инструментов, освобождённых от требования согласия — сверяйтесь с актуальным перечнем, а не с записью в блоге, но на бумаге это реальное преимущество.

GoAccess — вариант, который никто не советует, а стоило бы многим. Он читает журнал доступа, который ваш веб-сервер уже ведёт, и превращает его в отчёт в терминале или в единую самодостаточную HTML-страницу. В браузере ничего не выполняется, на устройстве ничего не хранится, и вопрос согласия не возникает, потому что сбор данных не выходит за рамки самого запроса. Плата за это — всё, что происходит внутри страницы, и любая надежда считать людей, а не запросы. Для сайта документации или статичного блога это часто честный обмен — и его лучше сочетать с одним из остальных инструментов, а не заменять их им.

Решение в одну строку

Если вы не можете назвать конкретную функцию, которая вам нужна от Plausible или Matomo, значит, вам нужен Umami. Разверните его за двадцать минут, поработайте с ним месяц, и пусть то, на что вы не сможете найти ответ, само подскажет, стоит ли переходить. Более поздняя миграция обойдётся вам только потерей истории — и ничем больше, а терять там будет всего месяц истории.

Шаг 02 · Подготовка

Одна машина, одно имя. Сначала разберитесь с именем.

Заказывайте VPS и выбирайте бастион по тому, где находятся ваши читатели и где вы хотите, чтобы лежали данные, — Стокгольм, Хельсинки, Осло и Рейкьявик все находятся в пределах ЕЭЗ, и именно в этом смысл. Затем, прежде чем что-либо ещё коснётся машины, выполните защиту в первый час: SSH только по ключу, перенесённый порт, файрвол с политикой «запретить по умолчанию», автоматические обновления без участия человека. Это те же сорок минут для каждого руководства в этой серии, и они не являются опциональными на машине, которая будет хранить год чьей-то читательской аудитории.

Затем определитесь с именем хоста, потому что оно впаяно в код отслеживания на каждой странице каждого сайта, который вы измеряете, и изменить его позже означает редактировать их все, пока старое имя ещё продолжает получать запросы. Работают два варианта. Отдельный поддомен измеряемого сайта — обратный прокси на машине аналитики отвечает за него, и это самый простой вариант из работающих. Или нейтральное имя на собственном домене, если один экземпляр будет обслуживать несколько не связанных друг с другом сайтов и вы предпочитаете, чтобы исходный код одного сайта не выдавал существование остальных. Создайте запись и дайте ей время разрешиться, прежде чем двигаться дальше: прокси при первом запуске запрашивает сертификат у удостоверяющего центра, а тот проверяет имя снаружи.

dig +short stats.example.com          # must return the VPS address before you deploy
ufw default deny incoming
ufw allow 47222/tcp                  # administrative SSH, moved off 22
ufw allow 80/tcp                     # ACME challenge and the redirect to 443
ufw allow 443/tcp                    # the dashboard and the collection endpoint
ufw enable && ufw status numbered

Три порта, и больше ничего. Порт базы данных не должен быть опубликован: она живёт во внутренней сети Docker, доступной контейнеру приложения и никому больше из интернета. Это самая распространённая причина, по которой самостоятельно размещённая машина с аналитикой оказывается в результатах сканирования, — порт PostgreSQL или MySQL, привязанный к публичному адресу, потому что в Compose-файле из туториала была секция сопоставления портов, которая была нужна только для локальной разработки.

Что касается размера — не поддавайтесь желанию взять с запасом больше, чем нужно. Sentinel — 2 vCPU, 4 GB, 120 GB NVMe, $3.90 в месяц — запускает Umami вместе с Postgres с запасом по ресурсам и удержит годы событий для сайта с шестизначным числом просмотров в месяц. Переходите на Garrison — 4 vCPU, 8 GB, 240 GB, — если выбрали Plausible, потому что ClickHouse там чувствует себя лучше, или Matomo, потому что задаче архивирования нужны дополнительные ядра. Трафик безлимитный на любом тарифе, а трафик аналитики на его фоне — статистическая погрешность: каждое событие — это всего несколько сотен байт.

Шаг 03 · Установка

Два контейнера и прокси. Затем закройте дверь.

Эталонное развёртывание ниже — это Umami, потому что именно его стоит запускать большинству читателей и потому что эта структура обобщается: контейнер приложения, контейнер базы данных, до которого может добраться он и никто другой, и обратный прокси, который держит сертификат. Plausible и Matomo отличаются числом контейнеров и именами переменных, но не структурой — возьмите их официальные Compose-файлы и примените те же три правила.

Три правила, в порядке того, во сколько обойдётся их нарушение. Закрепляйте каждый образ за точным тегом, никогда за «плавающим»: стек аналитики, который незаметно подтягивает новую major-версию во время не связанной с этим перезагрузки, — это миграция схемы, которую вы не планировали. Генерируйте секрет приложения из настоящего источника случайности и храните его — он шифрует данные сессий, а его смена в лучшем случае разлогинит всех сразу. Не публикуйте порт базы данных: два контейнера делят одну сеть, и этого достаточно для всего необходимого им контроля доступа.

mkdir -p /srv/analytics && cd /srv/analytics
openssl rand -base64 32 > .app_secret      # keep this file; back it up with the database
openssl rand -base64 24 > .db_password
chmod 600 .app_secret .db_password

Compose-файл. Два сервиса, одна приватная сеть, один именованный volume для базы данных и ни одного опубликованного порта — с внешним миром говорит только прокси:

services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-v2.x.y   # an exact tag, never :latest
    environment:
      DATABASE_URL: postgresql://umami:CHANGE_ME@db:5432/umami
      APP_SECRET:   CHANGE_ME                                # the openssl output above
    depends_on: [db]
    restart: unless-stopped
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB:       umami
      POSTGRES_USER:     umami
      POSTGRES_PASSWORD: CHANGE_ME
    volumes:
      - umami-db:/var/lib/postgresql/data
    restart: unless-stopped
volumes:
  umami-db:

Caddy — самый короткий путь к правильной настройке TLS в этом случае: две строки конфигурации, сертификат, который получается и обновляется без cron-задачи, и современные значения по умолчанию, которые не нужно изучать отдельно. Если на машине уже работает nginx, оставьте nginx — требуется прокси перед приложением, а не именно этот прокси. В любом случае приложение аналитики никогда не должно быть тем, что слушает порт 443 напрямую.

# Caddyfile — Caddy runs as a third service in the same Compose project, so
# "umami" resolves on the internal network. It is the only service that
# publishes ports (80 and 443).
stats.example.com {
    encode zstd gzip
    reverse_proxy umami:3000
}

Поднимите стек, а затем сразу сделайте то единственное, что по-настоящему критично по времени. docker compose up -d, дождитесь миграций и откройте дашборд. Каждый из этих инструментов поставляется либо с документированной учётной записью администратора по умолчанию, либо с открытым экраном первой регистрации, а имя хоста стало публично известным в тот момент, когда был выпущен сертификат, потому что журналы прозрачности сертификатов публичны и постоянно сканируются. Смените пароль по умолчанию и закройте регистрацию в течение первых минут после успешной первой загрузки, а не завтра.

docker compose up -d
docker compose logs -f umami          # wait for the schema migration to finish
docker compose ps                     # both services healthy, no published ports listed
ss -tlnp | grep -E ':(5432|3306)'     # must print nothing at all
Пять минут, которые решают, кому принадлежит экземпляр

Umami поставляется с документированной учётной записью администратора, пароль которой одинаков на каждой установке в мире. Первый посетитель Plausible становится владельцем, если регистрация не отключена через переменные окружения. Matomo проводит первого посетителя через установщик, который создаёт суперпользователя. Во всех трёх случаях промежуток между «сертификат существует» и «вы вошли в систему» — это промежуток, в течение которого войти может кто-то другой вместо вас, — и угадывать имя хоста ему не придётся, потому что оно и так опубликовано. Сначала войдите сами, смените учётные данные, затем переведите переключатель регистрации в положение «закрыто» и обновите страницу, чтобы убедиться, что изменение применилось.

Шаг 04 · Инструментирование

Один тег. Дальше решите, на чьём домене он будет жить.

Зарегистрируйте сайт в дашборде, скопируйте выданный идентификатор и вставьте в шаблон один тег script с атрибутом defer — в head или в конце body, не так уж важно, где именно, но в любом случае с defer, чтобы он никогда не задерживал загрузку страницы. Это и есть вся интеграция целиком. Здесь нет ни менеджера тегов, ни контейнера, ни data layer, ни настройки consent-режима, и именно это отсутствие — по большей части то, ради чего вы сюда и пришли.

<script defer src="https://stats.example.com/script.js"
        data-website-id="00000000-0000-0000-0000-000000000000"></script>

Загрузите страницу сайта, а затем откройте дашборд: событие должно появиться там в течение нескольких секунд. Если этого не произошло, консоль браузера и вкладка network дадут ответ менее чем за минуту — два типичных сбоя это неверно указанный идентификатор, из-за которого запрос принимается и отбрасывается, и запрос, который вообще никуда не уходит, — а значит, его «съело» расширение браузера. Исключите собственный трафик, прежде чем начинать читать цифры, иначе ваши же перезагрузки страницы неделю будут вашим главным источником переходов.

Теперь — решение, над которым стоит подумать. Фрагмент выше делает запрос к хосту, который не принадлежит самому сайту, а часть ваших посетителей использует программы, блокирующие такие запросы по шаблону. Списки фильтров вылавливают известные имена файлов — всё, что заканчивается на собственное имя script у вендора — и известные хостинговые домены, независимо от того, на какой сервер они на самом деле указывают. У исправления два компонента: переименовать файл script и конечную точку сбора данных во что-то, что не похоже на имя трекера — это поддерживает каждый из этих инструментов, — и раздавать их с собственного источника (origin) сайта через путь, который уже перенаправляет ваш существующий прокси. После этого стороннего запроса, который можно было бы блокировать, просто не остаётся.

# On the site's own web server — the two paths the tracker needs, first-party:
example.com {
    handle /p/s.js      { reverse_proxy https://stats.example.com { header_up Host stats.example.com } }
    handle /p/collect   { reverse_proxy https://stats.example.com { header_up Host stats.example.com } }
    # ... the rest of the site
}

Две детали определяют, заработает это полностью или лишь наполовину. Прокси должен передавать адрес посетителя в заголовке, которому приложение аналитики настроено доверять, иначе каждое обращение будет приписано вашему собственному веб-серверу, и отчёт по странам превратится в один-единственный столбик. И трекеру нужно сообщить, куда отправлять данные, — это data-атрибут на теге script во всех трёх инструментах: если переименовать файл, не перенастроив при этом эндпоинт, вы получите script, который загружается, но никуда не отправляет отчёты.

Это же и есть честный предел всей истории измерений. Посетитель с отключённым JavaScript или со строгим списком блокировки плюс правилом, блокирующим даже first-party-скрипты, не будет учтён, и на попытки поймать его не стоит тратить сколько-нибудь инженерных усилий — фильтр на уровне сети — это осознанно заявленное предпочтение, и вежливый ответ на него — журнал сервера, который учитывает такого посетителя, не собирая ничего сверх того. События и одностраничные приложения — это вторая половина инструментирования: каждый инструмент предоставляет небольшую функцию для пользовательских событий, и каждому из них нужен явный вызов при смене маршрута, потому что фреймворк, который меняет отображаемое содержимое без навигации, не создаёт загрузки страницы, которую скрипт мог бы заметить.

Шаг 05 · Соответствие

Два закона, а не один. Большая часть интернета их путает.

Причина, по которой люди не могут договориться, нужен ли аналитике баннер, в том, что они спорят о двух разных правилах, как если бы это было одно правило. Разделите их — и ответ становится понятным. Статья 5(3) Директивы об электронной приватности (ePrivacy) — перенесённая в национальное законодательство каждого государства-члена и являющаяся истинным источником баннера cookie — говорит, что для сохранения информации на терминальном оборудовании абонента или для получения доступа к уже сохранённой там информации требуется его согласие, если это не строго необходимо для предоставления услуги, которую он явно запросил. Обратите внимание, чего эта статья не говорит: она не говорит cookie, и она не говорит персональные данные. Она распространяется на localStorage, распространяется на fingerprinting устройств, и применяется даже к значению, которое никого не идентифицирует.

GDPR — второе правило, и оно регулирует другой вопрос: что вы можете делать с персональными данными, когда они у вас уже есть. Оно применяется к вашей аналитике независимо от того, храните ли вы что-либо на устройстве, потому что веб-запрос передаёт IP-адрес, а Суд ЕС в деле Breyer (C-582/14) установил, что IP-адрес может быть персональными данными в руках оператора сайта. Так эти два правила складываются друг с другом: статья 5(3) спрашивает, записывали ли вы что-то на устройство, а GDPR спрашивает, что вы сделали с тем, что получили.

Сервер аналитики без cookie создан, чтобы отвечать на оба эти вопроса, и отвечать узко. Он ничего не хранит на устройстве — ни cookie, ни записи в localStorage, ни какого-либо идентификатора — а значит, статья 5(3) здесь не применяется, потому что нет ни хранения, ни доступа к хранилищу. При этом он берёт IP-адрес, который неизбежно получает, объединяет его с User-Agent, сайтом и секретной солью, которая меняется каждый день, хеширует результат, сохраняет хеш и отбрасывает сам адрес. Этот хеш позволяет инструменту отличать двух посетителей друг от друга в течение одного дня и становится бесполезным в момент смены соли — именно поэтому тот же человек завтра засчитывается как новый посетитель. Обработка данных здесь реальна, но она настолько мала, насколько это вообще возможно.

Что остаётся — это правовое основание для этой узкой операции обработки, и на практике операторы опираются на законный интерес по статье 6(1)(f), документированный кратким оценочным тестом баланса интересов, который короткий именно потому, что факты просты: никакого профилирования, никакой передачи третьим лицам, никакого межсайтового отслеживания, псевдоним, который умирает каждый день, чётко определённый срок хранения. Некоторые надзорные органы пошли дальше и опубликовали критерии, по которым строго ограниченное измерение аудитории полностью освобождается от требования согласия, — критерии различаются по странам, они обновляются, и важен для вас именно тот, что действует в вашей стране. Это не юридическая консультация. Это карта того, какие правовые инструменты применяются, — чтобы консультация, которую вы получите, касалась вашей конкретной ситуации, а не общей формы проблемы.

Вопрос Тег рекламной аналитики Без cookie, с самостоятельным размещением в ЕЭЗ
Записывает что-то на устройство посетителя?Да — поэтому требуется согласие по статье 5(3)Нет — статья 5(3) не применяется
Хранится долгоживущий идентификатор?От месяцев до лет, между разными сайтамиХеш с солью и суточным сроком действия
Нужно документировать передачу в третью страну?Да, с механизмом передачи данных, который нужно поддерживатьОтсутствует — машина находится в ЕЭЗ
Обработчики, которых нужно назвать и включить в договорПоставщик и его субобработчикиВаш хостинг-провайдер — за оборудование, и никто больше
Кто может ответить на запрос субъекта данныхВы — через тот экспорт, который естьВы, с помощью SQL — и часто там просто нечего возвращать

В досье стоит держать ещё одну строку, потому что именно в ней — негромкий аргумент в пользу всей этой затеи. Законность передачи данных европейских посетителей американскому сервису аналитики оспаривается в судах уже десятилетие: Суд ЕС отменил предыдущую схему передачи данных по делу Schrems II (C-311/18) в 2020 году, несколько национальных надзорных органов на этом основании признали стандартный тег аналитики незаконным в 2022 году — Австрия в январе, Франция в феврале, Италия в июне, за ними последовали другие, — а новое решение об адекватности, EU-US Data Privacy Framework, восстановило маршрут передачи данных в июле 2023 года и само сейчас находится под угрозой оспаривания. Вам не нужно иметь собственное мнение о том, чем это закончится. Машина в Хельсинки снимает этот вопрос из вашего досье навсегда, а это стоит больше, чем быть правым насчёт текущего состояния дел.

Шаг 06 · Хранение

Сроки хранения, резервные копии, обновления. И журнал, о котором вы забыли.

Настройте срок хранения данных в первый же день, пока это ещё абстрактное число, а не год данных, к которым вы уже привязались. Каждый из этих инструментов умеет удалять необработанные события по расписанию, сохраняя сводные агрегаты; двенадцати месяцев детализации достаточно почти для любой цели, а это значит, что честный ответ на вопрос «как долго вы это храните» — конкретное число, а не «бессрочно». Это также решает проблему места на диске ещё до того, как она возникнет, что особенно важно для Matomo, чьи исходные таблицы растут быстрее остальных.

Делайте резервную копию базы данных не на этой же машине и шифруйте её при передаче — полное описание есть в руководстве по бэкапам, а короткая версия такая: ночной дамп, передаваемый в репозиторий с добавлением только в конец (append-only) на второй машине, желательно в другой юрисдикции. Сохраняйте резервную копию секрета приложения вместе с ней: база данных, которую можно восстановить, и секрет, который нельзя, — это дашборд, в который никто не сможет войти. Затем восстановите её один раз на тестовый VPS осознанно, до того как это понадобится по-настоящему.

docker compose exec -T db pg_dump -U umami umami | zstd -q -o /srv/backup/umami-$(date -u +%F).sql.zst
restic -r sftp:backup@bastion-2:/srv/repo backup /srv/backup /srv/analytics/.app_secret
restic -r sftp:backup@bastion-2:/srv/repo forget --keep-daily 7 --keep-weekly 8 --prune

Обновления заслуживают немного больше внимания, чем обычное обновление версии контейнера, потому что эти приложения владеют своей схемой данных. Прочитайте заметки о выпуске для всех major-версий, через которые вы перепрыгиваете, сделайте резервную копию заранее, а не постфактум, затем смените закреплённый тег и поднимите стек, наблюдая за журналами, — миграция, которая наполовину провалилась, восстанавливается из вчерашнего дампа и оказывается очень неприятной без него. Нет никакой причины устанавливать самый новый релиз в неделю его выхода, и есть весьма веская причина не делать этого.

Журнал, который сводит на нет всю затею

Вы только что развернули стек, который намеренно никогда не хранит IP-адрес. А в двух метрах от него ваш обратный прокси записывает полный IP-адрес каждого без исключения посетителя в журнал доступа, в открытом виде, и хранит его столько, сколько задано ротацией по умолчанию, — причём это касается и машины с аналитикой, и веб-сервера перед вашим настоящим сайтом. Этот журнал — больший и более чувствительный набор данных, чем сама база данных аналитики, это операция обработки, за которую вам придётся отвечать, и почти никто о ней не помнит. Решите, для чего он нужен: если только для отладки — обрезайте или маскируйте последний октет в формате журнала и агрессивно ротируйте его; если он нужен вам для измерений на основе журнала — укажите это в политике и задайте ему реальный срок хранения. Чего точно не следует делать — это оставить настройки по умолчанию и при этом описывать свой сайт как не собирающий IP-адреса.

И наконец — об ограничениях стоит сказать честно, потому что самостоятельно размещённый счётчик — не строго лучшая версия того, что вы убрали. Вы теряете идентификацию между устройствами и между днями, поэтому вернувшийся посетитель означает нечто более узкое, чем прежде. Вы теряете интеграцию с рекламной платформой, что важно, если вы покупаете трафик, и не важно, если нет, — данные Search Console — отдельный продукт, и это на них не влияет. Вы берёте на себя обновления и резервное копирование, а это реальные повторяющиеся затраты, измеряемые вечерами. А сама машина становится тем, что стоит защищать: на ней хранятся данные о вашей аудитории, она находится в публичном интернете, и чек-лист по защите вместе с приватным маршрутом к дашборду — это две вещи, которые не дают ей превратиться в проблему.

Заметки с практики · Шесть ловушек

Шесть способов, которыми это может пойти не так. Два из них — незаметные.

Ловушка 01 · Фатальная

Пароль по умолчанию, который знают все

Один из этих инструментов поставляется с одинаковой учётной записью администратора на каждой установке в мире; остальные отдают права владения тому, кто зарегистрируется первым. Имя хоста публикуется в журналах прозрачности сертификатов в тот момент, когда заработал TLS. Войдите, смените пароль, закройте регистрацию — в первые пять минут, а не завтра.

Ловушка 02 · Фатальная

Порт базы данных из туториала

Compose-файлы, написанные для ноутбука, публикуют порт 5432 или 3306, чтобы автор мог подключиться из GUI-клиента. Скопируйте такой файл на публичную машину — и таблица с данными о читателях окажется на расстоянии одного подбора пароля. Контейнер приложения обращается к базе данных через внутреннюю сеть; публиковать не нужно ничего, кроме прокси.

Ловушка 03 · Правовая

Предположение, что самостоятельный хостинг освобождает от требований

Перенос ПО на собственную машину отвечает на вопрос о международной передаче данных и на вопрос об обработчике. Но он не отвечает на вопрос по статье 5(3), если вы включите функцию, которая записывает что-то на устройство, и он не пишет вашу политику конфиденциальности за вас. Освобождение от требований — это свойство конфигурации, а не хостинга.

Ловушка 04 · Тихая

Все посетители — из одной и той же страны

Обратный прокси, который не передаёт адрес клиента, заставляет каждый запрос выглядеть так, будто он пришёл от самого прокси. Дашборд заполняется, итоговые числа выглядят правдоподобно, а столбцы географии и уникальности посетителей на самом деле — фикция. Проверяйте разбивку по странам в первый же день, а не при квартальном обзоре.

Ловушка 05 · Тихая

Журнал доступа, который вы всё ещё ведёте

Этот стек был выбран, потому что он никогда не хранит IP-адрес. Прокси перед ним по умолчанию хранит их все в открытом виде, и то же самое делает веб-сервер перед вашим настоящим сайтом. Маскируйте или ротируйте их осознанно и описывайте это в политике — или перестаньте утверждать, что вы их не собираете.

Ловушка 06 · Предотвратимая

Погоня за старыми цифрами

Новые итоговые цифры не совпадут со старыми, и никакая настройка этого не изменит. Разные правила подсчёта, разная доля заблокированного трафика, и никакой баннер больше не отфильтровывает выборку. Потратьте две недели на то, чтобы понять своё собственное соотношение, а затем воспринимайте новую цифру как точку отсчёта и перестаньте сверять два разных определения.

Вопросы и ответы · Самостоятельно размещённая аналитика

Вопросы, и ответы на них.

Одиннадцать вопросов, которые возникают в процессе, — начиная с того, в котором все ошибаются сразу в обе стороны.

Можно ли действительно отказаться от баннера cookie при самостоятельном хостинге?

Часто — да, и причина точнее, чем просто «я хостю сам — значит, всё в порядке». Здесь действуют два отдельных правила. Статья 5(3) Директивы об электронной приватности (ePrivacy) — та самая, которую все называют «законом о cookie», — требует согласия на то, чтобы сохранять информацию на устройстве посетителя или считывать её оттуда, если это не строго необходимо для услуги, которую он сам запросил. Она применяется к cookie, но также к localStorage, к sessionStorage и к чему угодно ещё, что вы оставляете на устройстве, и применяется независимо от того, являются ли эти данные персональными. Инструмент, который ничего не записывает на устройство, попросту не подпадает под её действие. GDPR — второе правило, и оно никуда не исчезает: вы всё равно получаете IP-адрес и строку User-Agent при каждом запросе, а IP-адрес является персональными данными в руках оператора сайта (Суд ЕС, дело Breyer, C-582/14). Сервер аналитики без cookie хеширует этот IP с солью, которая меняется каждый день, а затем отбрасывает сам адрес, так что в базе данных оказывается посуточный, привязанный к конкретному сайту псевдоним, а не человек. Это узкая, хорошо документированная операция обработки данных, на которую большинство операторов ссылаются как на законный интерес, и несколько надзорных органов опубликовали критерии, по которым чистое измерение аудитории освобождается от требования согласия. Это защитимая позиция, а не волшебное слово: зафиксируйте письменно, что вы собираете, зачем и как долго, и читайте разъяснения именно вашего регулятора, а не лендинг вендора. Ничего на этой странице не является юридической консультацией.

Какой инструмент выбрать, если не хочется об этом думать?

Umami. Это одно Node-приложение и одна база данных PostgreSQL, ему комфортно в пределах 1 GB памяти, дашборд понятен с первого посещения, он без cookie из коробки, и один экземпляр без проблем обслуживает все сайты, которые у вас есть. Для подавляющего большинства людей, заменяющих Google Analytics на блоге, сайте документации, в магазине или на корпоративном сайте, это правильный ответ, а необходимость выбирать между остальными тремя вариантами просто не возникает. Выбирайте вместо этого Plausible Community Edition, если вам нужны воронки, цели по выручке и более убедительная история с публичными дашбордами, и вы готовы ради этого запускать ClickHouse. Выбирайте Matomo, если вам по-настоящему нужен набор функций Google Analytics — сегменты, когорты, произвольные отчёты, атрибуция для электронной коммерции, импорт исходных журналов — и вы принимаете то, что будете обслуживать большое PHP-приложение с задачей архивирования по расписанию. Выбирайте GoAccess, если вы вообще не хотите JavaScript на странице.

Почему цифры не совпадают с Google Analytics?

Потому что они считают разные вещи, и разрыв идёт в обе стороны одновременно. В сторону увеличения: Google Analytics за баннером согласия видит только тех посетителей, кто нажал «принять», а в Европе это обычно около половины всех посетителей, тогда как счётчик без cookie и без баннера видит всех. Ещё в сторону увеличения: ваш новый эндпоинт находится на собственном домене и не входит в списки блокировщиков, отсекающие запросы к известным трекерам. В сторону уменьшения: ежедневно меняющийся хеш не может узнать того же человека на следующий день, поэтому читатель, зашедший в понедельник и в четверг, — это два посетителя, а не один вернувшийся, — сессии сшиваются только в пределах одного дня и никогда между днями или устройствами. Ещё в сторону уменьшения: большинство самостоятельно размещённых инструментов используют консервативный фильтр ботов и не дают инфляции в духе Discover. Практический совет — перестать сверять цифры. Запустите оба счётчика на две недели, чтобы узнать своё собственное соотношение, запишите его на бумажке, а затем удалите тег Google и используйте новые цифры как ту точку отсчёта, которой они теперь и являются. Для решений важна форма тренда и относительное ранжирование страниц и источников — и то, и другое переживает переход без изменений.

Будут ли блокировщики рекламы блокировать и мой собственный экземпляр?

Частично, и стоит точно понимать, как именно, потому что механизм устроен проще, чем принято думать. Крупные списки фильтров работают по шаблонам: по именам хостов хостинговых сервисов и по набору известных имён файлов и путей — запрос к чему-то, заканчивающемуся на plausible.js, umami.js или matomo.php, узнаётся независимо от того, на какой сервер он на самом деле идёт. Перенесите ПО на stats.example.com, оставив стандартные имена файлов, — и вы всё равно потеряете часть технически подкованной аудитории. Есть два честных способа исправить это, и они складываются друг с другом. Переименуйте script и конечную точку сбора данных во что-то, что не похоже на имя трекера — каждый из этих инструментов позволяет это сделать, и это стоит одной строки конфигурации. Раздавайте их с того же источника (origin), что и сам сайт, через путь на вашем основном домене, который перенаправляет обратный прокси, — тогда стороннего запроса, который можно было бы заблокировать, просто не остаётся. Вместе эти два способа возвращают большую часть потерь. Всё вы не вернёте, и не должны хотеть этого: посетитель, использующий строгий список вместе с отключённым JavaScript, сделал свой выбор, и правильный ответ на это — журнал сервера, а не гонка вооружений.

Является ли проксирование script через собственный домен «тёмным паттерном»?

Вопрос заслуживает внимания, и ответ зависит от того, что именно защищал блокировщик. У списка фильтров есть один грубый инструмент и две очень разные цели: рекламно-технологическая сеть, которая следует за человеком по десяти тысячам сайтов и строит профиль, и счётчик, который сообщает одному владельцу сайта, что его страницу документации вчера прочитали четыреста раз. Блокировка первой — это человек, защищающий себя от слежки. Блокировка второй — это побочный ущерб от правила, которое не может их различить. Раздача собственного счётчика с собственного домена — это не провоз трекера мимо защиты; это устранение стороннего запроса, которого вообще не должно было существовать, а строка в вашем журнале доступа появится от того же визита в любом случае. Граница защитимости проходит там, где то, что вы проксируете, — уже не то, что описано здесь: если вы добавляете межсайтовые идентификаторы, фингерпринтинг или канал передачи данных на рекламную платформу, блокировщик был прав, а прокси — это обман. Проверка простая, и её стоит хотя бы раз применить к себе: могли бы вы опубликовать страницу, точно описывающую, что собирает этот эндпоинт, — и читатель просто пожал бы плечами? Если да — проксируйте. Если нет — проблема не в прокси.

Насколько большим должен быть VPS на самом деле?

Меньше, чем вы боитесь, с одним исключением. Umami — это процесс Node и база данных Postgres: для обычного сайта он укладывается меньше чем в 1 GB памяти, а база данных растёт примерно на размер одной текстовой строки за просмотр страницы, так что у Sentinel — 2 vCPU, 4 GB, 120 GB NVMe, $3.90 в месяц — запаса на годы вперёд. GoAccess — статистическая погрешность. Matomo — посередине: PHP и MariaDB нетребовательны, пока не запускается задача архивирования, — это и есть тот всплеск нагрузки на CPU, под который нужно рассчитывать размер, — а его исходные таблицы растут быстрее остальных, потому что он хранит больше данных на каждое обращение. Исключение — Plausible Community Edition, и причина в ClickHouse, а не в самом Plausible: колоночная база данных по своей природе обменивает память на скорость запросов и заберёт себе всё, что вы оставите без ограничений. Он укладывается в 4 GB, если ограничить его кеши в поставляемой конфигурации, и чувствует себя комфортно на 8 GB — именно поэтому тариф Garrison за $7.90 является разумным минимумом именно для этого варианта. В любом случае число, которое в итоге вынуждает к обновлению тарифа, — это диск, а не память, и шаг 06 рассказывает, как это остановить.

Может ли один экземпляр измерять несколько разных сайтов?

Да, и это нормальный способ их использования. Все три JavaScript-инструмента изначально рассчитаны на несколько сайтов: вы регистрируете каждый домен в дашборде, каждый получает собственный идентификатор, и один и тот же эндпоинт script принимает события для всех них, сохраняя отчёты раздельно. Одна машина, один сертификат, одна резервная копия, одно обновление — двадцать сайтов. По мере роста списка стоит помнить о двух вещах. Отчёты разделены по сайтам, поэтому, если вы администрируете сайты для клиентов, используйте собственные права пользователей и команд инструмента, а не раздавайте всем подряд учётную запись администратора, и уточняйте, что подразумевает общий экземпляр, прежде чем соглашаться на это в договоре: вы становитесь стороной, которая хранит данные их посетителей. И конечная точка отслеживания — это общее имя, а значит, домен, который её обслуживает, появляется в исходном коде каждого сайта из списка, — факт, который стоит упомянуть клиенту, чьи конкуренты читают исходный код страницы, и лишний аргумент в пользу first-party-пути из шага 04.

Нужен ли мне вообще JavaScript? А что насчёт анализа журнала сервера?

Для большого класса сайтов журнала достаточно, и это самое честное измерение, какое только возможно: оно не собирает ничего сверх того, что уже существует в виде строк журнала. GoAccess читает журнал доступа веб-сервера и выдаёт отчёт в терминале или самодостаточный HTML-дашборд — топ страниц, источники переходов, коды статуса, объём трафика, время отклика, User-Agent — для статичного сайта, набора документации или API это покрывает почти всё, что мог бы рассказать вам тег script. Достаточность журнала для вас определяют два ограничения. Журнал не видит того, что происходит внутри страницы: ни глубины прокрутки, ни кликов по внешним ссылкам, ни событий кнопок, ни смены маршрутов в single-page-приложении, потому что ничего из этого не касается сервера. И журнал считает запросы, а не людей, так что вы во власти кеширования и популяции ботов, которая теперь составляет большинство необработанного трафика, — фильтрация становится постоянной задачей обслуживания, а не разовой настройкой. Есть и ловушка приватности, обратная той, что вы могли бы ожидать, и шаг 06 разбирает её: журнал, который вы анализируете, хранит полные IP-адреса — а это больше персональных данных, чем хранил отвергнутый вами JavaScript-инструмент.

Можно ли импортировать историю из Google Analytics?

Реалистично говоря — нет, и планировать с учётом этого лучше, чем бороться с этим. Из всех четырёх инструментов только у Matomo есть хоть сколько-нибудь серьёзная история импорта, и даже там практические пути — это импорт собственных журналов веб-сервера и использование инструментов миграции для старых установок Matomo, а не прямой перенос обработанных отчётов Google. Umami и Plausible Community Edition могут принять массовую загрузку через свои API, если вы готовы написать сопоставление полей, но по сути вы будете придумывать сессии и посетителей на основе агрегированных экспортов, и результатом будет график, который выглядит непрерывным, но не сопоставим в точке стыковки. Что действительно работает: экспортируйте нужные вам отчёты из Google, пока свойство ещё существует, — суммарные показатели по месяцам, топ страниц, топ источников, число конверсий — в формате CSV, храните их там же, где остальные ваши записи, и начните работу с новым инструментом с чистого листа, с даты, которую вы зафиксируете письменно. Вы обратитесь к старому экспорту дважды в первый год и больше никогда, тем более что каждое число в нём в любом случае измерено по другому определению.

Что мне на самом деле нужно написать в политике конфиденциальности?

Меньше, чем вы думаете, и в этой краткости — весь смысл: абзац, который вы способны отстоять, лучше страницы, которую вы скопировали. Скажите, что это за инструмент и что вы управляете им самостоятельно; укажите местоположение сервера и юридического оператора, потому что возможность сказать «на машине, которую мы арендуем в Финляндии» — это и есть весь смысл всей затеи. Скажите, что записывается при каждом визите: страница, источник перехода, страна, устройство и семейство браузера, а также псевдонимный идентификатор, полученный из IP-адреса и User-Agent с солью, которая меняется каждый день, — и из этого идентификатора исходный IP восстановить нельзя. Скажите, что не записывается: ни cookie, ни межсайтовый идентификатор, ни профиль, никакие данные не продаются и не передаются. Укажите правовое основание, на которое вы опираетесь, и срок хранения — и убедитесь, что указанное число совпадает с тем, на которое настроен сам инструмент. Если ваш обратный прокси хранит журналы доступа, это отдельная операция обработки со своим собственным сроком хранения — упомяните и её, потому что о ней обычно забывают. И далее держите этот абзац синхронизированным с реальной конфигурацией: политика, описывающая настройку, которая была два года назад, хуже, чем расплывчатая формулировка.

Почему важно, кто хостит машину, на которой хранятся только просмотры страниц?

Потому что фраза «это всего лишь просмотры страниц» недооценивает, что на самом деле представляет собой база данных аналитики. За год накопления это уже читательская аудитория вашего сайта: какие страницы, в каком порядке, из каких стран, в какие часы, по каким ссылкам — а для небольшого издания или нишевого магазина это, в одной таблице, и бизнес-план, и список источников. С точки зрения юрисдикции это именно тот тип данных, который злоумышленник запросит у провайдера, а не у вас. Отсюда следуют два свойства. Место, где стоит машина, определяет, какая правовая процедура до неё доберётся: машина в Стокгольме, Хельсинки, Осло или Рейкьявике находится в пределах ЕЭЗ, что полностью снимает вопрос международной передачи данных с вашей повестки соответствия, и находится в пределах четырёх конституционных режимов с сильными традициями свободы прессы. А то, чьё имя стоит на счёте, определяет, что раскрывает сам счёт: у NordBastion нет ни документа, удостоверяющего личность, ни юридического имени, ни карты, счёт оплачивается в Monero или Bitcoin, а машина, хранящая данные о вашей аудитории, — не строка в чьей-то клиентской базе данных с приложенным к ней вашим паспортом. Руководство по юрисдикциям подробно разбирает правовой минимум каждой из этих четырёх стран.

Получите машину

Ваша читательская аудитория — на машине в ЕЭЗ, которая не зарегистрирована на ваше имя.

Sentinel — 2 vCPU, 4 GB и 120 GB NVMe за $3.90 в месяц, в Хельсинки, Стокгольме, Осло или Рейкьявике — запускает Umami вместе с его базой данных с запасом на годы событий. Переходите на Garrison за $7.90, если выбрали Plausible или Matomo. Никакой почты при регистрации, никакого документа, удостоверяющего личность, никакой карты и никакой третьей стороны, хранящей список всех, кто хоть раз читал ваш сайт.

Последняя проверка · 2026-10-12 · Источники · Документация Umami, Plausible Community Edition, Matomo и GoAccess; статья 5(3) Директивы об электронной приватности 2002/58/EC; Регламент (ЕС) 2016/679; решения Суда ЕС по делам Breyer (C-582/14) и Schrems II (C-311/18); решение об адекватности EU-US Data Privacy Framework от июля 2023 года · Периодичность · ежегодно

Приватный хостинг, построенный на Севере.