What is PostHog?
PostHog is an open source product analytics platform. Beyond page views, it captures user events and gives you funnels, retention, session replay, heatmaps, feature flags, A/B testing, surveys and a data warehouse in one tool. It is the most popular open source alternative to Mixpanel, Amplitude and Hotjar, and its self-hosted "hobby" deployment is MIT licensed.
Know what you are signing up for. The hobby deployment is a large Docker Compose stack: ClickHouse, Kafka, PostgreSQL, Redis, Temporal, object storage, a dozen PostHog services and Caddy for HTTPS. PostHog provides no support or guarantees for it, and says plainly that PostHog Cloud is usually cheaper for most teams.
Requirements
- An Ubuntu server equivalent to Hetzner's 4 vCPU, 16 GB RAM machine, with more than 30 GB of storage. The installer warns that 8 GB is the absolute minimum.
- A domain with an A record pointing at the server's public IP. The installer refuses IP addresses because it needs a real certificate.
- Ports 80 and 443 open to the internet.
Step 1: Prepare the server
Start from a fresh Ubuntu server. The script installs Docker and a standalone docker-compose binary if they are missing. Create a folder and point DNS at the server first, so the certificate can be issued on the first try:
mkdir -p ~/posthog-hobby && cd ~/posthog-hobby
dig +short posthog.example.com # must print this server's IP
Step 2: Create the Docker Compose file
PostHog generates the Compose file for you. The official command pipes a script into bash with sudo, so download it and read it before running it:
curl -fsSL https://raw.githubusercontent.com/posthog/posthog/HEAD/bin/deploy-hobby -o deploy-hobby
less deploy-hobby
bash deploy-hobby
The script asks for a version (press Enter for latest) and your domain, then:
- clones the PostHog repo and copies
docker-compose.hobby.ymltodocker-compose.yml, along withdocker-compose.base.yml; - writes
.envwith a randomPOSTHOG_SECRETandENCRYPTION_SALT_KEYS, plus optional AI API keys if you enter them; - downloads a GeoIP database and starts the stack with Caddy on ports 80 and 443.
It also sends an install event containing your domain to PostHog's own analytics. Keep .env safe: losing ENCRYPTION_SALT_KEYS makes encrypted data such as integration credentials unreadable.
Step 3: Start and open the app
The first start pulls many images and runs migrations; the script waits up to 10 minutes for the web container to report healthy. Follow along in another terminal:
cd ~/posthog-hobby && sudo docker-compose logs -f web
When it is up, open https://posthog.example.com and create the first account immediately, since the first person to sign up owns the instance. Copy the project API key and the snippet from the onboarding screen into your site or app, then watch events arrive under Activity.
Step 4: Put it behind HTTPS
HTTPS is already handled: the proxy service is Caddy, which obtains a Let's Encrypt certificate for your domain. What remains is closing ports you did not ask for. The hobby Compose file publishes Temporal on 7233 and the Temporal UI on 8081 on all interfaces. Docker-published ports bypass ufw, so a host firewall rule will not hide them. Block everything except 22, 80 and 443 in your cloud provider's firewall, or change those two mappings in docker-compose.yml to 127.0.0.1:7233:7233 and 127.0.0.1:8081:8080. Note that the upgrade script regenerates the Compose file, so a cloud firewall is the more durable fix.
Backups and upgrades
Back up .env, the Postgres database (users, projects, dashboards, feature flags) and the ClickHouse data (events):
sudo docker-compose exec -T db pg_dump -U posthog posthog > posthog-pg-$(date +%F).sql
For ClickHouse, the reliable option on a single server is a disk snapshot from your hosting provider, or stopping the stack and copying the clickhouse-data Docker volume.
To upgrade, run the official script from the same folder:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/posthog/posthog/HEAD/bin/upgrade-hobby)"
PostHog no longer cuts tagged releases for hobby installs, so upgrades move you to the latest code. Take a snapshot first.
Troubleshooting
- Health check times out after 10 minutes: usually not enough RAM. Check
free -handsudo docker-compose psfor containers that exited, thensudo docker-compose logsfor the failing one. - Certificate errors: DNS did not point at the server when Caddy started. Fix DNS and run
sudo docker-compose restart proxy. - Events do not appear: check the browser console for blocked requests (ad blockers block PostHog), and confirm the snippet uses your domain as
api_host. - Disk fills up: ClickHouse and Kafka grow with event volume. Add storage or reduce session replay sampling.
Next steps
Set up a reverse-proxied ingestion path on your own domain to reduce ad-blocker losses, configure email over SMTP for invites, create your first funnel and feature flag, and decide early whether your volume justifies moving to PostHog Cloud.
Spotted something out of date? Tell us and we will update the guide.