SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-16

Self-hosted вебаналітика на VPS: що обрати

Порівняння Plausible, Umami, Matomo, GoatCounter і GoAccess: 1 або 2 GB RAM, вибір бази даних, ріст диска, reverse proxy та обмеження ad blocker.

Який self-hosted інструмент вебаналітики варто запустити на VPS?

Self-hosted вебаналітика поділяється на два типи. Неправильний вибір типу коштує дорожче, ніж неправильний вибір продукту. Один тип запускає невеликий скрипт у браузері відвідувача та зберігає дані, які цей скрипт надсилає. Інший тип читає access log, який вебсервер уже записує. Усе інше, зокрема база даних і потрібний обсяг пам’яті, залежить від цього вибору.

Коротка відповідь для невеликого сервера. GoatCounter і Medama працюють на 1 GB, оскільки кожен із них є одним процесом і використовує один файл. Umami додає контейнер Postgres і надає dashboard, зрозумілий користувачу без технічних знань. Plausible Community Edition і Rybbit використовують ClickHouse, тому плануйте щонайменше 2 GB RAM. Matomo — це повнофункціональний продукт, для якого потрібен сервер, розмір якого відповідає вашому обсягу трафіку. GoAccess взагалі нічого не додає на сторінку, оскільки читає вже наявний log.

Тег скрипту або журнал сервера: що саме бачить кожен із них

Тег скрипту вимірює дії браузерів. Сторінка завантажується, скрипт запускається, а потім надсилає один запит до вашого збирача даних. Якщо будь-яка ланка цього ланцюжка не працює, ви цього не побачите: JavaScript вимкнено, список фільтрації блокує запит, запит до збирача завершився помилкою або crawler не запускає скрипти.

Парсер журналів вимірює запити. Вебсервер записує один рядок для кожного запиту незалежно від того, встановили ви додаткове програмне забезпечення чи ні, тому дані вже зберігаються на диску. Він бачить кожного crawler і кожне звернення до файлу, який не містить тега скрипту. Він не бачить, що відбувається всередині браузера. Також він не бачить сторінку, яку віддано з кешу браузера або CDN (content delivery network) перед вашим сервером, оскільки такий запит не надійшов на ваш сервер.

Ці два числа не збігатимуться, і жодне з них не є помилковим. Matomo може виконувати обидва типи вимірювання. У документації Matomo зазначено, яких даних імпорт журналів не дає порівняно з JavaScript tracker: роздільної здатності екрана та заголовків сторінок, подій, відстеження контенту, теплових карт, записів сеансів і аналітики форм. Це обмеження є наслідком підрахунку запитів, а не браузерів.

Трафік від ботів — інша частина цієї різниці. Підрахунок на основі журналів включає crawler, якщо їх не фільтрувати. На звичайному сайті частка crawler достатньо велика, щоб змінити ваші висновки. GoAccess і імпорт журналів у Matomo фільтрують відомих ботів. Жоден із них не може відфільтрувати crawler, який підробляє свій user agent. Тому підрахунок на основі журналів варто поєднувати з блокуванням AI crawler на сервері і читати журнал після блокування, а не до нього.

GoAccess: аналітика наявних журналів

Встановіть його з власного репозиторію проєкту для Debian та Ubuntu, оскільки пакети дистрибутива відстають від актуальних релізів.

wget -O - https://deb.goaccess.io/gnugpg.key | gpg --dearmor | sudo tee /usr/share/keyrings/goaccess.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/goaccess.gpg arch=$(dpkg --print-architecture)] https://deb.goaccess.io/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/goaccess.list
sudo apt-get update
sudo apt-get install goaccess

Після цього передайте йому шлях до журналу та створіть статичний звіт.

goaccess /var/log/nginx/access.log -o ~/report.html --log-format=COMBINED

Для звичайного користувача ця команда завершується помилкою Permission denied, оскільки в Ubuntu журнал nginx належить root, а його група — adm. Додайте свій обліковий запис до цієї групи за допомогою sudo usermod -aG adm $USER, потім вийдіть із системи та увійдіть знову, оскільки членство в групах зчитується під час входу. Виконайте id і переконайтеся, що adm є у списку, перш ніж повторити спробу.

Звіт за поточним журналом охоплює лише записи, які logrotate ще не перемістив. Запити за вчора зберігаються у access.log.1, а старіші журнали стиснуто, тому для тижневого звіту потрібно також прочитати ротовані файли.

zcat /var/log/nginx/access.log.*.gz | goaccess - --log-format=COMBINED -o ~/last-week.html

Є також режим реального часу — --real-time-html, який оновлює сторінку через WebSocket. Для нього потрібні додатковий порт і окреме правило проксі. Для більшості сайтів достатньо щогодинного звіту, який створює cron, і такий варіант потребує менше заходів захисту.

GoatCounter: один бінарний файл Go і один файл SQLite

GoatCounter постачається як статично скомпільований бінарний файл, тому встановлювати середовище виконання не потрібно. Завантажте збірку зі сторінки релізів і запустіть її або використайте image.

docker run -p 8080:8080 -v goatcounter-data:/home/goatcounter/goatcounter-data arp242/goatcounter

У разі запуску як бінарного файла goatcounter serve прослуховує порт 8080 і створює базу SQLite у ./goatcounter-data/db.sqlite3. Якщо інстанс уже працює за проксі, створіть перший сайт з командного рядка, а не через вебмайстер.

goatcounter db create site -vhost=stats.example.com -user.email=me@example.com

GoatCounter може самостійно керувати сертифікатом за допомогою goatcounter serve -listen=:443 -tls=tls,rdr,acme, використовуючи ACME (середовище автоматичного керування сертифікатами). Це зручно на сервері, де більше нічого не працює. Якщо портом 443 уже керує nginx або Caddy, залиште GoatCounter на порту 8080 і проксируйте запити до нього. За власною оцінкою проєкту, скрипт відстеження має розмір близько 3.5K. Для сторінок без JavaScript передбачено tracking pixel. Якщо SQLite стає обмеженням для завантаженого сайту, той самий бінарний файл може працювати з Postgres за допомогою goatcounter serve -db 'postgresql+dbname=goatcounter'. Резервні копії створюються простим копіюванням файла. Саме це є головною перевагою такої архітектури інструмента.

Medama: один контейнер, який заявляє про використання 256 MB

Medama — найновіший варіант із одним бінарним файлом у цьому огляді. За задумом він не використовує cookie, а в описі проєкту вказано трекер розміром менше ніж 1 KB і можливість роботи невеликих сайтів на віртуальних машинах із 256 MB пам’яті. Це опубліковані твердження проєкту, а не дані, виміряні для цього посібника.

docker volume create medama-data
docker run -d -p 127.0.0.1:8080:8080 -v medama-data:/app/data ghcr.io/medama-io/medama:latest

Офіційна команда публікує порт як 8080:8080. Префікс loopback вище вказано навмисно; у розділі про reverse proxy пояснюється причина. Перший вхід виконується з admin і паролем CHANGE_ME_ON_FIRST_LOGIN, а назва цього пароля є інструкцією.

На вас чекає один документований сценарій збою. Вхід працює лише через HTTPS або на localhost. Тому якщо налаштувати проксі до отримання сертифіката, форма відхилить правильний пароль, але причину не буде виведено. Спочатку завершіть налаштування TLS (transport layer security), а потім увійдіть.

Umami: Postgres і знайома користувачам панель

git clone https://github.com/umami-software/umami.git
cd umami
docker compose up -d

Це запускає застосунок на порту 3000 разом із контейнером PostgreSQL. Документація вказує PostgreSQL v12.14 як мінімальну підтримувану версію. Якщо натомість збирати застосунок із вихідного коду, потрібен Node.js 18.18 або новіший. Є готовий образ docker.umami.is/umami-software/umami:postgresql-latest. Для нього потрібно задати DATABASE_URL, що має вказувати на базу даних, яку ви вже запускаєте.

Для першого входу використовуйте admin і пароль umami. Змініть пароль до того, як спрямувати DNS на цей сервер. Щойно запис почне повертати адресу сервера, а проксі почне відповідати, інстанс стане доступним з інтернету. Докладні відомості про Compose, файли середовища та політику перезапуску див. у матеріалі стек Docker Compose на VPS, а не копіюйте конфігурацію, якої не читали.

Розгортання складається з процесу Node і Postgres. Це важче, ніж один бінарний файл, але значно легше за будь-яке рішення, що використовує ClickHouse.

Plausible Community Edition: ClickHouse визначає мінімальний обсяг RAM

git clone -b v3.2.1 --single-branch https://github.com/plausible/community-edition plausible-ce
cd plausible-ce
touch .env
echo "BASE_URL=https://stats.example.com" >> .env
echo "SECRET_KEY_BASE=$(openssl rand -base64 48)" >> .env
docker compose up -d

Станом на August 2026 актуальною є версія v3.2.1, і команда клонування навмисно фіксує саме її. Стек складається з трьох частин: застосунку, Postgres для облікових записів і налаштувань та ClickHouse для даних подій. SECRET_KEY_BASE має містити щонайменше 64 байти. Саме такий рядок створює виклик openssl.

Власні вимоги Plausible передбачають щонайменше 2 GB RAM, щоб ClickHouse і застосунок не були завершені OOM killer, а також CPU з підтримкою SSE 4.2 або NEON, яка потрібна ClickHouse. Другу вимогу варто перевірити до придбання VPS. Це одна з практичних відмінностей у виборі між ARM і x86 VPS. ClickHouse також використовує стільки пам’яті, скільки вважає доступною. Тому на спільному сервері встановіть обмеження, як описано в обмеженні пам’яті контейнера в Compose.

BASE_URL має точно відповідати публічній URL-адресі. Якщо це не так, ви входите в систему, застосунок перенаправляє на неправильний хост, а cookie сеансу записується для домену, на якому браузер не перебуває. У результаті ви повертаєтеся до форми входу без повідомлення про помилку.

Файл Compose, що постачається разом із застосунком, не публікує порт, оскільки передбачається використання проксі. Додайте override-файл, який публікує стандартний порт застосунку лише на loopback.

cat > compose.override.yml << EOF
services:
    plausible:
        ports:
            - 127.0.0.1:8000:8000
EOF

Matomo: повний продукт і серверні вимоги

Matomo працює на PHP із MySQL або MariaDB, тому належить до класичного вебстека, а не до стека контейнерів. Це також єдиний інструмент у цьому огляді, для якого опубліковано рекомендації щодо апаратного забезпечення залежно від обсягу трафіку.

ChartMatomo sizing guidance by monthly pageviews
The data behind this chart
[
  {
    "label": "100K/month",
    "cpu_cores": 2,
    "ram_gb": 2,
    "disk_gb": 50
  },
  {
    "label": "1M/month",
    "cpu_cores": 4,
    "ram_gb": 8,
    "disk_gb": 250
  },
  {
    "label": "10M/month",
    "cpu_cores": 8,
    "ram_gb": 16,
    "disk_gb": 400
  }
]

Це опубліковані Matomo мінімальні вимоги станом на August 2026, а не результати вимірювань для цього посібника. За обсягу до 100,000 переглядів сторінок на місяць потрібні 2 ядер CPU, 2 GB RAM і 50 GB SSD. Один сервер розміщує і застосунок, і базу даних. За 1M/month потрібно 8 GB RAM і 250 GB дискового простору. За 10M/month Matomo рекомендує два сервери. В останньому рядку наведено вимоги до сервера бази даних: 16 GB RAM і 400 GB дискового простору. Порівнюйте ці значення дискового простору з варіантами на одному бінарному файлі, де весь набір даних зберігається в одному файлі SQLite.

Найбільше проблем спричиняє архівування. За замовчуванням Matomo формує звіти, коли хтось відкриває dashboard. У міру зростання обсягу даних dashboard працює повільніше й зрештою завершується за тайм-аутом. Документований спосіб виправлення — вимкнути архівування, яке запускається браузером, у загальних налаштуваннях і запускати archiver через cron від імені користувача, якому належать файли Matomo, з каталогу Matomo.

php console core:archive --url=https://analytics.example.com

Matomo також зберігає таблиці з необробленими журналами поруч із таблицями оброблених звітів. Старі необроблені дані та старі звіти можна видаляти за розкладом. Увімкніть це під час інсталяції, а не після заповнення диска. Matomo також може імпортувати журнали доступу до сервера. Це єдиний продукт у цьому огляді, який одночасно охоплює обидва типи даних.

Rybbit і новіші стеки

git clone https://github.com/rybbit-io/rybbit.git
cd rybbit
chmod +x *.sh
./setup.sh your.domain.name

Rybbit — новий проєкт із сучасною панеллю керування. Скрипт налаштування записує файл середовища та запускає стек за допомогою Docker Compose. Він використовує ClickHouse і постачає Caddy як власний вебсервер. Caddy займає порт 443 і запитує сертифікат для домену, який ви вказали. Якщо на сервері портом 443 уже керує nginx, скрипт не зможе прив’язати порт. У такому разі використовуйте ручний спосіб запуску через Compose із документації проєкту та розмістіть Rybbit за наявним reverse proxy. У документації зазначено щонайменше 2 GB RAM, тестування на Ubuntu 24 LTS і вимогу ARMv8.2-A або новішої версії для ARM через використання ClickHouse.

Важливе застереження щодо будь-якого молодого проєкту: нові функції з’являються швидко, але так само швидко можуть з’являтися несумісні зміни. Зафіксуйте tag, прочитайте release notes перед оновленням і спочатку створіть резервну копію бази даних.

Ретенція та зростання обсягу даних: виміряйте їх на власному сервері

Зростання обсягу даних залежить від того, що саме інструмент зберігає для кожної події. GoatCounter агрегує перегляди в лічильники, тому його файл зростає переважно залежно від кількості унікальних сторінок і днів, а не від загального обсягу трафіку. Umami і Matomo зберігають окремі рядки для кожної події, а Matomo додатково зберігає оброблені таблиці звітів поверх необроблених даних. ClickHouse зберігає події в стовпцях і сильно їх стискає. Саме тому Plausible витримує обсяг даних, який створює значне навантаження на сховище на основі рядків.

У цьому посібнику не наведено показник у мегабайтах на мільйон переглядів сторінок, оскільки його не вимірювали на вашому трафіку. Виконайте вимірювання самостійно. Замініть назви сервісу та користувача відповідно до власного Compose-файлу.

du -h goatcounter-data/db.sqlite3
docker compose exec db psql -U umami -d umami -c "SELECT pg_size_pretty(pg_database_size('umami'));"
docker compose exec plausible_events_db clickhouse-client -q "SELECT formatReadableSize(sum(bytes_on_disk)) FROM system.parts WHERE active"

Зафіксуйте значення, зачекайте тиждень, зафіксуйте його ще раз і поділіть різницю на кількість переглядів сторінок, яку панель керування показує за цей тиждень. Це значення характеризує саме ваш сайт і ваші правила фільтрації ботів, тому воно корисніше за будь-яке опубліковане середнє значення. Після цього встановіть обмеження ретенції, поки показник ще невеликий. Заповнений диск виводить з ладу всі сервіси на VPS, а не лише аналітику. Це найвагоміший аргумент на користь розміщення тому бази даних у місці, про яке df -h вас попередить. Цьому ризику потрібно приділити більше уваги на сервері, де вже зберігаються великі об’єкти, оскільки self-hosted фотосервер заповнить диск задовго до того, як будь-яка база даних аналітики наблизиться до критичного обсягу.

Як це працює за reverse proxy на субдомені

Розмістіть collector на субдомені сайту, який він вимірює, наприклад stats.example.com. Тоді запит до collector вважається first-party, тому на нього не поширюються правила браузера, що блокують third-party запити.

Прив’яжіть застосунок до loopback під час публікації порту контейнера. Docker додає власні правила firewall перед правилами ufw, тому контейнер, опублікований як -p 3000:3000, доступний з інтернету, навіть якщо ufw status повідомляє, що порт заборонено. Перевірте це з іншої машини за допомогою curl http://SERVER_IP:3000 — ви отримаєте dashboard. Якщо опублікувати порт як -p 127.0.0.1:3000:3000, та сама перевірка поверне Connection refused, і доступ до нього матиме лише proxy.

server {
    listen 443 ssl;
    server_name stats.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Заголовки пересилання тут обов’язкові. Без X-Forwarded-For кожен візит надходитиме з адреси 127.0.0.1, тому звіт за країнами буде порожнім, а кількість унікальних відвідувачів наближатиметься до одного. Кожен проєкт визначає, якому заголовку він довіряє і за якого параметра. Тому один раз перегляньте документацію про proxy для цього проєкту, а не робіть припущень. Caddy самостійно встановлює ці заголовки, а Caddyfile для такого самого завдання містить два рядки.

stats.example.com {
    reverse_proxy 127.0.0.1:3000
}

Якщо ви ще не вибрали proxy, порівняння nginx, Caddy і Traefik допоможе визначити, який варіант підходить для одного сервера з кількома субдоменами.

Self-hosting змінює того, хто зберігає дані. Це не змінює вимог законодавства до обробки даних. Розрізняйте два правила. Вимога ePrivacy щодо згоди стосується зберігання або зчитування будь-яких даних на пристрої відвідувача. Тому інструмент, який не встановлює cookie і нічого не записує в local storage, не підпадає під цю конкретну вимогу. GDPR стосується обробки персональних даних. IP-адреса є персональними даними, тому вам усе одно потрібні правова підстава, строк зберігання та відповідь на запит про те, які дані ви зберігаєте про користувача.

Plausible, Umami, GoatCounter і Medama не встановлюють cookie за замовчуванням. Дані, які кожен із них натомість обчислює, відрізняються залежно від проєкту та змінюються між версіями. Тому читайте власну документацію про конфіденційність проєкту, а не покладайтеся на стислий огляд. Matomo постачається з анонімізацією IP-адрес і endpoint для відмови від відстеження, який потрібно ввімкнути в адміністративному інтерфейсі.

Регулятори в різних країнах доходять різних висновків. Наприклад, французька CNIL публікує умови, за яких вимірювання аудиторії може бути звільнене від вимоги отримувати згоду. Цей розділ є фактичним оглядом, а не юридичною консультацією. Для реального сайту з реальними користувачами зверніться до юриста у своїй юрисдикції.

Є ще один момент, який часто випускають із уваги: access log також містить персональні дані. GoAccess не додає скрипт на сторінку, але все одно обробляє IP-адреси. Тому аналітика на основі журналів не обов’язково виводиться за межі дії цих правил.

Блокувальники реклами та причини зниження показників

Фільтрувальні списки зіставляють ім’я хоста та шаблон URL. Hosted analytics product легко виявити, оскільки всі завантажують його з одного загальновідомого імені хоста. Перенесення collector на власний subdomain прибирає це ім’я хоста із запиту, а розміщення скрипту за вибраним вами шляхом прибирає загальновідоме ім’я файлу. Обидві зміни впливають на те, з чим саме має зіставлятися запис у списку.

У цій статті не наводиться hit rate, оскільки його не вимірювали. Частка відвідувачів, які блокують певну конфігурацію, залежить від вашої аудиторії. Аудиторія розробників блокує значно більше, ніж загальна аудиторія. Натомість виміряйте власну різницю. Протягом того самого тижня за допомогою GoAccess підрахуйте в access log запити до HTML-сторінок і порівняйте їх із кількістю pageviews, яку показує ваш інструмент на основі скрипту. Різниця на вашому сайті — це заблоковані відвідування та сторінки, віддані з кешу.

Очікуйте зміни загальних показників у день переходу з hosted product. Також враховуйте, що частина цієї зміни може не мати жодного стосунку до блокування. Різні продукти по-різному визначають pageview, по-різному враховують перехід між маршрутами всередині single-page application і по-різному визначають завершення сесії. Перш ніж робити висновок про падіння трафіку, порівняйте тенденції за кілька тижнів.

Що обрати для якого сайту

  • Для персонального сайту або блогу з приблизно до 50,000 переглядів сторінок на місяць: GoatCounter або Medama на VPS із 1 GB RAM, із резервними копіями у вигляді копій файлів.
  • Для сайту, де неможливо додати скрипт, або для аудиторії, яка активно його блокує: GoAccess на основі наявного журналу, за розкладом.
  • Для сайту малого бізнесу, де панель читає інша людина: Umami з його контейнером Postgres.
  • Для сайту, де потрібні цілі та воронки, на сервері з 2 GB RAM або більше: Plausible Community Edition або Rybbit, якщо потрібна новіша панель і ви готові використовувати молодший проєкт.
  • Для багатьох сайтів, багатьох облікових записів або вимоги зберігати необроблені дані відповідно до власної політики зберігання: Matomo, із ресурсами відповідно до наведених вище опублікованих рекомендацій.

Почніть із найпростішого інструмента, який відповідає на ваше фактичне запитання. Перехід із GoatCounter на Plausible пізніше коштуватиме вам субдомену та частини історичних даних. Перехід із Matomo на будь-який інший інструмент вимагатиме міграції, яку навряд чи захочеться виконувати. Якщо ви ще вирішуєте, що розмістити на тому самому сервері, ширший огляд self-hosting описує, що можна додати поруч із ним. Якщо ж насправді потрібне трасування запитів на рівні застосунку, а не підрахунок відвідувачів, для цього краще використовувати self-hosted сервіс спостережуваності.

FAQ

Ні, це два окремі питання. Вимога щодо згоди за ePrivacy стосується зберігання або читання даних на пристрої відвідувача. Тому інструмент, який не встановлює cookie і нічого не записує в local storage, не підпадає під цю конкретну вимогу. GDPR — інше правило, яке стосується обробки персональних даних. IP-адреса є персональними даними, тому навіть без cookie потрібні законна підстава та обмеження строку зберігання. Self-hosting переносить дані на ваш сервер і робить вас відповідальною за них стороною. Перевірте рекомендації свого регулятора та зверніться до юриста щодо вашого випадку.

Скільки RAM потрібно self-hosted аналітиці на VPS?

Потреби визначає сховище даних, а не dashboard. GoatCounter і Medama працюють як один процес з одним файлом. У документації Medama зазначено, що невеликі сайти працюють на машинах із 256 MB. Umami додає контейнер Postgres поруч із Node-застосунком. Plausible Community Edition і Rybbit використовують ClickHouse, і обидва проєкти вказують щонайменше 2 GB. Власні рекомендації Matomo починаються з 2 ядер CPU і 2 GB RAM для обсягу до 100,000 переглядів сторінок на місяць.

Чому показники self-hosted аналітики нижчі, ніж в аналітики, яку я замінив?

Є дві причини, і обидві реальні. Filter lists блокують частину запитів до collector, тому будь-який інструмент на основі скриптів втрачає ці відвідування. Продукти також рахують по-різному, оскільки визначення перегляду сторінки та момент завершення сесії в них відрізняються. Порівняйте кількість HTTP-запитів до HTML-сторінок за один тиждень у access log із кількістю переглядів сторінок на основі скриптів за той самий тиждень. Різниця — це заблоковані відвідування та сторінки з кешу, виміряні на вашому сайті, а не взяті з опублікованого кимось показника.

Чи можна запустити Plausible або Rybbit на ARM VPS?

Обидва використовують ClickHouse. ClickHouse потребує SSE 4.2 на x86 або NEON на ARM. У вимогах Plausible зазначено саме це, а в документації Rybbit вказано, що ARM-системам потрібен ARMv8.2-A або новіший. Сучасні ARM server cores відповідають цій вимозі, а старіші — ні. Помилка проявляється як відмова ClickHouse запускатися з повідомленням про набір інструкцій, а не як помилка в application log. На невеликому ARM-сервері single-file інструменти усувають це питання, оскільки жоден із них не запускає ClickHouse.

Чи варто аналізувати server logs замість використання tracking script?

Використовуйте аналіз log, якщо не можете додати скрипт, якщо ваша аудиторія активно блокує tracking або якщо потрібна кількість, що включає crawler-и. GoAccess читає log, який сервер уже записує, тому не додає ваги сторінці й не потребує бази даних. Ви втрачаєте все, що відбувається всередині браузера. Також ви не бачите сторінки, які віддаються з CDN або browser cache, оскільки такий запит не доходить до сервера. Багато сайтів використовують обидва підходи та розглядають їх як два різні вимірювання.