MAATRIX / Блог / PostHog в Docker Compose: готовый файл

PostHog в Docker Compose: готовый файл

MAATRIX

Продуктовая аналитика обычно означает три-четыре разных SaaS: одно для воронок, другое для записи сессий, третье для feature flags, четвёртое для A/B-тестов — и счёт в конце месяца, растущий вместе с трафиком. PostHog собирает всё это в одном инструменте и отдаёт исходники под лицензией, разрешающей self-host. Ниже — рабочий docker-compose.yml, с которым PostHog поднимется на вашем сервере без танцев с бубном вокруг очереди сообщений и объектного хранилища.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что за зверь PostHog и почему self-host — это компромисс

PostHog — open-source платформа продуктовой аналитики: event-трекинг, воронки (funnels), анализ удержания (retention), записи сессий (session replay), feature flags, A/B-эксперименты и SQL-доступ к сырым событиям через HogQL. Всё в одном UI, без склейки данных между разными сервисами через API.

У PostHog два пути: PostHog Cloud — управляемый SaaS с бесплатным лимитом событий в месяц, дальше платно за объём; и Open Source (self-hosted) — тот же движок через Docker Compose или Helm-чарт для Kubernetes.

Здесь важна честность: сам PostHog в документации прямо пишет, что self-hosted через docker-compose годится для тестов, небольших и средних нагрузок, но не даёт всех enterprise-фич облака (часть SSO-интеграций, продвинутый скейлинг очередей) и требует, чтобы вы сами следили за апдейтами. При потоке в тысячи событий в секунду присмотритесь к managed-варианту или готовьтесь масштабировать компоненты вручную. Для проекта с трафиком от сотен до десятков тысяч посетителей в сутки self-host на одном VPS — рабочий и предсказуемый вариант.

Технически стек — это не один контейнер, а связка сервисов:

  • PostHog (Django + Python) — веб-приложение, API, приём событий (capture).
  • PostgreSQL — метаданные: пользователи, проекты, feature flags, настройки воронок.
  • ClickHouse — колоночное хранилище самих событий, на нём построены быстрые агрегации по миллионам строк. Почему для аналитики берут колоночные БД — разобрано в статье ClickHouse против PostgreSQL для аналитики.
  • Redis — очереди задач, кэш, сессии Celery-воркеров.
  • Kafka + Zookeeper — шина событий между capture и ClickHouse (в части версий заменяется облегчённым режимом).
  • MinIO / S3-совместимое хранилище — для session replay записей и экспортов.
  • Celery worker / plugin-server — фоновая обработка, вебхуки, плагины.

Звучит громоздко — и это правда громоздко по сравнению с Plausible или Matomo. Плата за богатый функционал — больше частей, которые нужно кормить памятью.

Требования к серверу

Это не лёгкая аналитика на 2 ГБ. ClickHouse, Kafka и Postgres одновременно держат заметный объём в памяти даже без реального трафика.

РесурсМинимум (тест/dev)Комфортно (прод, малый-средний трафик)
RAM8 ГБ16 ГБ и больше
CPU2 vCPU4 vCPU
Диск40 ГБ SSD80-100+ ГБ NVMe
ОСUbuntu 24.04 / Debian 12

Цифры ориентировочные — расход зависит от потока событий и от того, как долго храните session replay (самый прожорливый по диску компонент). На 8 ГБ стек стартует и работает, но под нагрузкой первыми упрутся в память Kafka и ClickHouse — OOM-килы в docker compose logs обычно сигнал докупить RAM, а не чинить конфиг.

Понадобится современный Docker с Compose Plugin:

curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker
docker compose version

И домен с A-записью на IP сервера — без HTTPS браузеры будут ругаться на трекер, а некоторые фичи (cookieless-режим, cross-domain tracking) требуют защищённого соединения по умолчанию.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Готовый docker-compose.yml

Официальный репозиторий posthog/posthog содержит готовый compose-файл для «hobby»-развёртывания — на нём основана эта конфигурация, слегка упрощённая. Кладём рядом docker-compose.yml и .env в одном каталоге:

services:
  db:
    image: postgres:15-alpine
    restart: unless-stopped
    volumes:
      - pg-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: posthog
      POSTGRES_PASSWORD: ${POSTHOG_DB_PASSWORD}
      POSTGRES_DB: posthog

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data

  zookeeper:
    image: confluentinc/cp-zookeeper:7.6.1
    restart: unless-stopped
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181

  kafka:
    image: confluentinc/cp-kafka:7.6.1
    restart: unless-stopped
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_LOG_RETENTION_HOURS: 24

  clickhouse:
    image: clickhouse/clickhouse-server:24-alpine
    restart: unless-stopped
    depends_on:
      - kafka
      - zookeeper
    volumes:
      - ch-data:/var/lib/clickhouse
    ulimits:
      nofile:
        soft: 262144
        hard: 262144

  objectstorage:
    image: minio/minio:latest
    restart: unless-stopped
    command: server /data --console-address ":9001"
    volumes:
      - minio-data:/data
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}

  posthog:
    image: posthog/posthog:release-1.x
    restart: unless-stopped
    depends_on:
      - db
      - redis
      - kafka
      - clickhouse
      - objectstorage
    env_file:
      - .env
    ports:
      - "127.0.0.1:8000:8000"

  worker:
    image: posthog/posthog:release-1.x
    restart: unless-stopped
    command: /compose/start
    depends_on:
      - posthog
    env_file:
      - .env
    environment:
      DEPLOYMENT: worker

volumes:
  pg-data:
  redis-data:
  ch-data:
  minio-data:

Тег release-1.x — заглушка, актуальный нужно сверить в Docker Hub posthog/posthog — проект обновляется часто, и подставлять «latest» вслепую в проде не стоит: лучше зафиксировать конкретную версию. Порт PostHog опубликован только на 127.0.0.1 — наружу его отдаёт reverse proxy по HTTPS.

Теперь .env — минимальный набор переменных для рабочего инстанса:

POSTHOG_DB_PASSWORD=сложный_пароль_для_postgres
SECRET_KEY=сгенерируйте_случайную_строку_50+_символов
SITE_URL=https://analytics.example.com

DATABASE_URL=postgres://posthog:сложный_пароль_для_postgres@db:5432/posthog
REDIS_URL=redis://redis:6379/
KAFKA_HOSTS=kafka:9092
CLICKHOUSE_HOST=clickhouse
CLICKHOUSE_DATABASE=posthog
CLICKHOUSE_SECURE=false
CLICKHOUSE_VERIFY=false

OBJECT_STORAGE_ENABLED=true
OBJECT_STORAGE_ENDPOINT=http://objectstorage:9000
OBJECT_STORAGE_ACCESS_KEY_ID=${MINIO_ROOT_USER}
OBJECT_STORAGE_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}
OBJECT_STORAGE_BUCKET=posthog

MINIO_ROOT_USER=posthog-admin
MINIO_ROOT_PASSWORD=ещё_один_сложный_пароль

DISABLE_SECURE_SSL_REDIRECT=true
IS_BEHIND_PROXY=true

SECRET_KEY сгенерировать проще всего так:

openssl rand -base64 48 | tr -d '\n'

IS_BEHIND_PROXY=true и DISABLE_SECURE_SSL_REDIRECT=true нужны потому, что HTTPS терминирует reverse proxy перед контейнером, а не сам Django — без этих флагов PostHog уйдёт в бесконечный редирект сам на себя. Бакет posthog в MinIO нужно создать один раз через консоль MinIO (порт 9001) — без него не заработают session replay и экспорты, хотя базовый event-трекинг поднимется и без него.

Reverse proxy и SSL

Caddy — самый быстрый путь к рабочему HTTPS без ручного certbot. Если он ещё не стоит, разберите установку в статье про Caddy с авто-SSL на Ubuntu 24.04, здесь — минимальный конфиг под PostHog.

/etc/caddy/Caddyfile:

analytics.example.com {
    reverse_proxy 127.0.0.1:8000
}
sudo systemctl reload caddy

Если на сервере уже поднят Traefik как основной reverse proxy для нескольких контейнерных проектов, добавить PostHog туда через labels проще, чем городить второй прокси рядом — принципы разобраны в статье Traefik как reverse proxy для Docker.

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

Поднимаем стек по частям — если запустить всё разом, PostHog может стартовать раньше, чем Kafka и ClickHouse успеют подняться, и уйдёт в рестарт-луп:

docker compose up -d db redis zookeeper kafka clickhouse objectstorage
sleep 30
docker compose up -d posthog worker
docker compose logs -f posthog

Первый старт — самый долгий: PostHog накатывает миграции в Postgres и создаёт схему в ClickHouse, это может занять несколько минут. Когда контейнер перестанет перезапускаться и в логах пойдут обычные HTTP-запросы, откройте https://analytics.example.com — появится форма создания первого аккаунта, он же администратор инстанса.

Дальше — стандартный flow: создать проект (Project), скопировать Project API Key из его настроек и подключить SDK на стороне сайта или приложения.

Для веба проще всего поставить npm-пакет posthog-js и инициализировать его двумя строками:

import posthog from 'posthog-js'

posthog.init('ВАШ_PROJECT_API_KEY', { api_host: 'https://analytics.example.com' })

Для статичного сайта без сборки готовый <script>-сниппет лежит прямо в настройках проекта (Project Settings → Install this integration), копируется одной кнопкой. Для бэкенда и мобильных платформ есть отдельные SDK: posthog-node, posthog-python, posthog-ios, posthog-android.

Feature flags, A/B-тесты и session replay

Это то, ради чего многие переходят с чистой веб-аналитики на PostHog — набор фич выходит за рамки "посмотреть трафик".

  • Feature flags — включение функций для процента пользователей или конкретных сегментов без деплоя нового кода. Флаг создаётся в UI, проверяется в коде через posthog.isFeatureEnabled('new-checkout').
  • A/B-эксперименты — надстройка над feature flags: PostHog сам считает статистическую значимость между вариантами по выбранной метрике конверсии.
  • Session replay — запись действий пользователя на странице (клики, скролл, движение мыши) с воспроизведением как видео. Именно эти записи льются в MinIO/S3 и быстрее всего съедают диск — на активном сайте счёт может пойти на гигабайты в неделю. Ограничьте retention записей в настройках проекта, если диск ограничен.
  • HogQL — SQL-подобный язык запросов прямо по сырым событиям в ClickHouse, без экспорта данных наружу.

Каждая из этих фич по отдельности есть в специализированных SaaS (LaunchDarkly для флагов, Hotjar для replay, Optimizely для A/B), но в одном self-hosted инстансе — это единая система идентификации пользователя и меньше интеграционной возни.

Обновление, бэкапы и обслуживание

Обновление — пересборка образов и рестарт с сохранением миграций:

docker compose pull
docker compose up -d
docker compose logs -f posthog

Перед серьёзным апдейтом свериться с release notes на GitHub posthog/posthog не будет лишним — Kafka- и ClickHouse-схема иногда меняются между релизами.

Бэкапить нужно три вещи: Postgres (метаданные), ClickHouse (события) и MinIO-том (записи session replay, если используются):

docker compose stop posthog worker
docker run --rm -v posthog_pg-data:/data -v $(pwd):/backup alpine \
  tar czf /backup/posthog-pg-$(date +%F).tar.gz -C /data .
docker run --rm -v posthog_ch-data:/data -v $(pwd):/backup alpine \
  tar czf /backup/posthog-ch-$(date +%F).tar.gz -C /data .
docker compose start posthog worker

Для регулярных автоматических бэкапов, а не ручных при апдейте, посмотрите готовую схему в статье как настроить бэкап Docker volume на VPS — там же разобрана ошибка со снятием бэкапа "на живую" без остановки контейнера. Отдельно стоит следить за диском: логи Kafka и ClickHouse со временем накапливаются, если retention не ограничен — раз в месяц проверяйте docker system df.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли поднять PostHog без Kafka, чтобы упростить стек?

В части версий PostHog есть облегчённый режим без отдельной Kafka, но это зависит от конкретной версии образа — проверяйте документацию posthog/posthog перед тем, как убирать сервис, иначе capture перестанет работать.

Чем self-hosted PostHog отличается от облачного по функциям?

Движок тот же, но часть enterprise-возможностей (продвинутый SSO, автоматическое горизонтальное масштабирование очередей) доступна только в облаке или платном self-hosted тарифе — уточняйте актуальный список на сайте PostHog.

Что делать, если после docker compose up -d posthog контейнер уходит в рестарт-луп?

Чаще всего причина — PostHog стартовал раньше, чем ClickHouse или Kafka успели подняться. Смотрите docker compose logs clickhouse kafka отдельно, а PostHog поднимайте вторым шагом.

Session replay сильно грузит клиентский браузер?

Заметно меньше полноценной видеозаписи — PostHog пишет DOM-события, а не пиксели, но на тяжёлых SPA-страницах прирост нагрузки ощутим. Если критично, replay можно включить выборочно.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →