Self-host PostHog

Last updated:

|Edit this page

This page covers our free, open-source Docker compose deployment, which is available under a MIT license without guarantee. We continue to develop this version, but some premium features are only available on PostHog Cloud. We do not provide support for this "Hobby" version.

We no longer support paid, open-source deployments and it is no longer possible to buy licenses for self-hosted versions - we instead recommend migrating to PostHog Cloud.

Our MIT-licensed Docker compose deployment is best suited to internal tools, or evaluating features without vendor approval. It's also great for hobby projects which don't need advanced tools. For all other use cases, we recommend you use PostHog Cloud, which comes with a generous free tier.

Requirements

  • You have deployed a Linux Ubuntu Virtual Machine.
    • We highly recommend an instance with at least 8GB of RAM to handle any surges in event volume
  • You have set up an A record to connect a custom domain to your instance.
    • PostHog will automatically create an SSL certificate for your domain using LetsEncrypt

New deployments of PostHog's paid open source product using Kubernetes are no longer supported.

Configuration

There are various ways to configure and personalize your PostHog instance to better suit your needs. In this section you will find all the information you need about settings and options you can configure to get what you need out of PostHog.

Setting up the stack

To get started, all we need to do is run the following command, which will spin up a fresh PostHog deployment for us automatically!

Terminal
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/posthog/posthog/HEAD/bin/deploy-hobby)"

You'll now be asked to provide the release tag you would like to use, as well as the domain you have connected to your instance.

This release tag is the DockerHub tag and doesn't refer to the sunsetted Helm chart releases

Once everything has been setup, you should see the following message:

We will need to wait ~5-10 minutes for things to settle down, migrations to finish, and TLS certs to be issued
⏳ Waiting for PostHog web to boot (this will take a few minutes)

PostHog will wait here on a couple of tasks that need to be completed, which should only take a couple minutes.

Once this is complete, you should be able to see your PostHog dashboard on the domain you provided!

If you notice this step taking longer than 10 minutes, it's best to cancel it with Ctrl+C and take a look at the troubleshooting section.

Customizing your deployment (optional)

By default, the docker-compose.yml file that gets run comes with a series of default config values that should work for most deployments. If you need to customize anything, you can take a look at the full list of environment variables. After making any changes, simply restart the stack with docker-compose.

Additionally, if you would like to run a different version of PostHog, you can change the tag for the web, worker, and plugins services. Check out here for a list of all available tags.

Troubleshooting

If you have already run the one-step deployment command above and something went wrong, this section covers a number of steps you can take to debug issues.

Checking that all containers are running

We can use docker ps to check that all of our services are running.

Terminal
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
21a2f62d6e50 posthog/posthog:release-1.39.1 ... 1m ago Up 1m ... ...
77face12d3e2 posthog/posthog:release-1.39.1 ... 1m ago Up 1m ... ...
3b4bc7394049 posthog/posthog:release-1.39.1 ... 1m ago Up 1m ... ...
03f393c7aa84 caddy:2.6.1 ... 1m ago Up 1m ... ...
f1060c3d8d73 clickhouse/clickhouse-server:22.3 ... 1m ago Up 1m ... ...
7d2353a6bddf bitnami/kafka:2.8.1-debian-10-r99 ... 1m ago Up 1m ... ...
72051397040e zookeeper:3.7.0 ... 1m ago Up 1m ... ...
ff42ccf14481 redis:6.2.7-alpine ... 1m ago Up 1m ... ...
402a0eef69ae postgres:12-alpine ... 1m ago Up 1m ... ...
da0d115dd02e minio/minio ... 1m ago Up 1m ... ...

You should see all the same containers as above. If any containers aren't showing up or show that they've restarted recently, it's worth checking their logs to see what the issue is.

Checking the logs of each container

We can use the following command to check the logs for each of our containers.

Terminal
docker logs <container_name>

The best place to start looking is in the web container, which runs all the database migrations and will produce an error if any have failed.

Running into issues with deployment? Ask a question here or check out our community page to get help.

Upgrading

To upgrade, you can run the upgrade-hobby script from the PostHog repo.

Terminal
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/posthog/posthog/HEAD/bin/upgrade-hobby)"

Warning: Before upgrading, make sure you have created back-ups of all your data!

Our recommendation is to keep your PostHog deployment up-to-date. While we avoid breaking changes wherever possible we may sometimes deprecate or add features that require you to update to the latest version. You can track our latest updates in the changelog.

Migrating

If your server is struggling, you can either increase your instance size or move to PostHog Cloud for a hands-off experience

Questions?

  • rahul
    2 days ago

    Forbidden (403) CSRF verification failed. Request aborted.

    I have self hosted posthog on GCP and integrated into my next js application currently am facing "Forbidden (403) CSRF verification failed. Request aborted" for the below api calls where events are getting captured Request URL: https://{Url}/i/v0/e/?ip=1&_=1741776541825&ver=1.224.0&compression=gzip-js Request Method: POST Status Code: 403 Forbidden

  • Alex
    18 days ago

    401 Unauthorized on /api/billing causing looping login

    Thanks for fixing the recent issues with cyclotron and clickhouse. I finally got the self-hosted app running and have signed up successfully. However, I can't get past the login screen. Looking at the web-1 logs, the login is successful (username and pw is okay) but eventually authorization fails at the requests to /api/billing/get_invoices and /api/billing. Did I miss a step? Any advice what I can do?

    (Not sure if it has anything to do with it, I'm accessing the app running on the EC2 instance via http://{IP address}, not using https://{domain name}. I'm using Experimental mode.)

  • Paul
    22 days ago

    This does not take 5-10 minutes!

    Unless you are using a quantum computer

    • Paul
      Author20 days ago

      Not even got to trying tracking yet but that doesn't sound good. Eurgh

  • KARTIK
    a month ago

    Search For Properties and Event not working

    I have self deployed and the event tracking is working fine but i can't search anywhere directly I have checked the network tab the search api give no result but HogQL work and give applies that filter what should I do in this case ?

    Screenshot 2025-02-13 at 5.26.03 PM.png

  • triplenty
    a month ago

    web-1 Container Encountered Errors

    The following error happens:

    File "/code/posthog/async_migrations/migrations/0002_events_sample_by.py", line 154, in is_required
    table_engine = sync_execute(
    ^^^^^^^^^^^^^
    IndexError: list index out of range

    I checked the code, this line tries to query table "events" while it's not created in postgres. Then I checked an previous error, it seems the container is trying to send requests to clickhouse, but using the "localhost:9000" which seems to be wrong since localhost is pointing to container itself instead of clickhouse container.

    | File "/python-runtime/clickhouse_driver/connection.py", line 417, in connect
    | raise err
    | clickhouse_driver.errors.NetworkError: Code: 210. Connection refused (127.0.0.1:9000)

    The only change I made to clickhouse container is changing it's tag to 24.11.3.66 because version 24.10 encountered an error

    • Andy
      21 days ago

      Apologies for these issues, folks. As per comments on the other thread above, they should be resolved now. Let us know if you still run into problems.

  • triplenty
    a month ago

    Default Proxy Settings Seems to Be Wrong

    the web-1 container has logs like:

    {'event': "\n You indicated your instance is behind a proxy (IS_BEHIND_PROXY env var),\n but you haven't configured any trusted proxies. See\n https://posthog.com/docs/configuring-posthog/running-behind-proxy for details.\n ", 'timestamp': '2025-02-07T16:48:52.541553Z', 'logger': 'posthog.settings.access', 'level': 'warning', 'pid': 7, 'tid': 140265971866496}
    • Devin
      a month ago

      Were you able to fix the issue?

    • Harish
      a month ago

      I see this also, but it didn't seem to stop the app from running when I last was able to get it to work.

  • triplenty
    a month ago

    deploy error

    the container cyclotron-fetch-1 and cyclotron-janitor-1 starts failed. Docker logs shows that "database "cyclotron" does not exist"

    should I manually create the database?

    • Harish
      a month ago

      I am also interested in the solution to this.

      What this means (I think) in practice is that when I try to run an asynchronous job to e.g. sync data with a different source, it never does it.

  • Tama
    2 months ago

    Forbidden and CORS error

    I've got errors of forbidden and CORS to my self-hosted PostHog already tried to add ALLOWED_HOST inside the docker-compose.yml for the web container but the issues are still not solved

    image (6).png

    • Vlad
      2 months agoSolution

      After some investigation I found the workaround: Add NEW_ANALYTICS_CAPTURE_EXCLUDED_TEAM_IDS: 1 environment variable to web container in docker-compose file, So all capture events will go throw /e/ endpoint

  • imran
    5 months ago

    self hosted on aws ubuntu

    Validation checks

    9 successful, 1 error

    Plugin server · Node is showing error.

    any way to debug it? https://tinyurl.com/ymlzlfso

  • Moha
    6 months ago

    Installation error ghcr.io no such host

    I tried setup of PostHog and it gave below error:

    "Error response from daemon: Get "https://ghcr.io/v2/": dialing ghcr.io:443 with direct connection: resolving host ghcr.io: lookup ghcr.io: no such host"

    And there was also Kakfa error.

    Any solution to fix this please?

    • Alex
      6 months agoSolution

      It seems like your setup on WSL (Windows Subsystem for Linux) is almost complete since the containers are running, but you’re unable to access the PostHog dashboard due to the domain configuration issue. Here are some steps you can try:

      Access via Localhost: Since you didn't specify a domain name, PostHog should default to using localhost. To access the PostHog dashboard, open your browser and navigate to http://localhost:8000. If you're not able to access it, make sure that port 8000 is exposed to your WSL and accessible from your browser. Check Port Forwarding: If the above step doesn't work, WSL might not have properly configured port forwarding from WSL to your Windows system. You can explicitly forward the port by running the following command in your WSL terminal:

      sudo iptables -I INPUT -p tcp --dport 8000 -j ACCEPT

      Then, try accessing the PostHog dashboard again on http://localhost:8000. Verify Docker Setup: Ensure that Docker is correctly configured and the PostHog containers are running with the correct network settings. Use the following command to check the status of your Docker containers:

      docker ps

      Make sure that the containers for PostHog (typically posthog_web, posthog_worker, and posthog_plugins) are running. TLS Certificates: If the message "waiting for TLS certs to be issued" persists, it could mean that you're using HTTPS without a domain. For local development, it is recommended to stick with HTTP unless you're using a domain with valid TLS certificates. You can try explicitly configuring PostHog to use HTTP by setting DISABLE_HTTPS=1 in your environment variables. Access the Logs: To investigate further, you can check the logs for potential issues by running:

      docker-compose logs

      This will provide more insights if something is going wrong with the containers, migrations, or TLS certificates. If the issue persists, please let me know, and we can explore additional steps.

  • Suraj
    6 months ago

    Command failing with error

    Running the set up command is failing with the following error:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/posthog/posthog/HEAD/bin/deploy-hobby)"

    Grabbing latest apt caches The operation couldn’t be completed. Unable to locate a Java Runtime that supports apt. Please visit http://www.java.com for information on installing Java.

    • Paul(he/him)
      6 months agoSolution

      Ah, great... if you want to run locally on a mac then the best bet is to follow the instructions here https://posthog.com/handbook/engineering/developing-locally

      Slightly more than you need just to evaluate but that will run on a Mac.

      Otherwise you'd need an ubuntu (virtual) machine to run the self host script.

      Thanks

  • Krishnadas
    10 months ago

    Spinning circle on loading posthog

    I recently installed the latest version of posthog. Now I am just seeing a spinning circle

    spinningph.png

    I am seeing HTTP 500 returned for /api/billing-v2/. On checking the web logs it is giving the following error

    File "/code/ee/billing/billing_manager.py", line 177, in get_billing if not addon["subscribed"]: KeyError: 'subscribed'

    How can I fix this issue ? I am using the installation script mentioned in this doc

  • Krishnadas
    10 months ago

    Upgrading Posthog JS

    I am trying to upgrade posthog JS to latest version. I deleted all my existing containers and re-ran the installation script mentioned in this doc to bring posthog up again. The package json in the downloaded files in posthog/ folder is saying posthog-js version as 1.131.2 but I am still getting served version 1.118.0. Why is this happening ? How do I get the absolute latest version of posthog in all components?

    • Krishnadas
      Author10 months agoSolution

      Installing from scratch on a completely fresh server fixed this. Not sure where the files were getting cached in the previous one

  • Krishnadas
    a year ago

    Unable to connect to external clickhouse

    I am trying to use an external clickhouse cluster with self hosted posthog. I have given my clickhouse hot in the environment variable. But i am not getting any tables created in my clickhouse server. The database posthog got created correctly. The cluster name is also posthog. If I keep the environment variables with my host value but also bring the built in clickhouse container up, I can see tables are created there. Is the clickhouse host url hardcoded somewhere in the code ?

    • Krishnadas
      Authora year agoSolution

      This is resolved after fixing an issue with clickhouse cluster

  • Krishnadas
    a year ago

    Frontend not loading

    I followed this article and got the containers up and running. Now my SSL wasnt working for some reason so I re ran the container with debug: 'true'. Now my frontend is not loading. I can see it is looking for JS files at mydomain.com:8234. It is failing with network error. I cant see any containers up in port 8234 in my machine. Any clue on this ?

    • Krishnadas
      Authora year agoSolution

      This is resolved after giving correct DNS name for creating SSL cert

  • khushi
    a year ago

    Issue with PostHog Upgrade Script

    We are currently experiencing an issue with the PostHog upgrade script for our self-hosted version. We have attempted to use the following script to upgrade PostHog:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/posthog/posthog/HEAD/bin/upgrade-hobby)"

    However, during the execution of the script, we encountered the following error:

    Error response from daemon: invalid reference format

    It appears that the script suddenly stopped with this error message. We have followed the provided instructions for upgrading, but we seem to be encountering this obstacle.

    Could you please guide us how we can successfully update our self-hosted version of PostHog? We appreciate any assistance or insights you can offer to resolve this issue promptly.

    Error screenshot: https://img.enacton.com/ShareX/2024/02/putty_qIlxKd3LD1.png

    Thank You.

    • khushi
      Authora year agoSolution

      Hello Geordie,

      I'm glad to inform you that the script is now working correctly. I've made the necessary updates to the Docker Compose file by replacing the image name, which was previously set as "image: :latest-release", with "image: posthog/posthog:latest".

      That was the only change needed.

      Please let me know if you encounter any issues, and I'll do my best to help you further.

  • Owain
    a year ago

    Upgrading posthog fails

    Everything is fine until it sets up docker compose...

    Error response from daemon: invalid reference format

    Full output

    Upgrading PostHog. This will cause a few minutes of downtime.
    Do you want to upgarde PostHog? [y/N] y
    OK!
    Checking for named postgres and clickhouse volumes to avoid data loss when upgrading from < 1.39
    Found postgres and clickhouse volumes, proceeding...
    Already up to date.
    Setting up Docker Compose
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
    100 43.5M 100 43.5M 0 0 114M 0 --:--:-- --:--:-- --:--:-- 114M
    Error response from daemon: invalid reference format
    • Geordie
      a year ago

      Try this:

      export REGISTRY_URL="posthog/posthog"
      /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/posthog/posthog/HEAD/bin/upgrade-hobby)"
  • Imad
    a year ago

    setting SECRET_KEY

    Is it possible to have a detailed guide on how to set the secret key. IT IS NOT CLEAR

  • Pirmin
    a year ago

    How can I configure PostHog to use own internal web port?

    We are currently running a VM with nginx and I need to set up PostHog under our proxy. However I can’t find how to change the PostHog web port. The installation crashes because PostHog wants to access a running port.

    • Hogger
      a year ago

      Self-hosted Docker version of Posthog runs within 'web' container on port 8000. This is defined in ./posthog/bin/docker-server with

      --bind 0.0.0.0:8000

      You can change this file and add mount to docker-compose.yaml to "overwrite" /code/bin/docker-server

      - ./posthog/bin/docker-server:/code/bin/docker-server

      Your Nginx proxy should replace the Caddy container which is not needed anymore.

  • Dishant
    a year ago

    Create more than one project in selfhosted solution since enterprise selfhost version is sunset?

    So as the enterprise version is sunset aka discontinued for onprem, how can we create multiple projects on selfhosted version.

    Currently on selfhosted version we can only create one project and organization.

    We want to setup multiple websites in the instance but don't want to create multiple instances for the same.

    • Marcus
      a year agoSolution

      Hey, those features are not accessible on the self-hosted version anymore. You could sign-up for the free version on PostHog cloud to get access to multiple organizations.

    • Mark
      a year ago

      @marcus. We aren't interested in you hosting for us. We are willing pay for a license for features we want. And evidently we aren't the only ones that desire this. Do you want to forego this revenue?

Was this page useful?

Next article

Instance settings

When self-hosting PostHog there are several instance settings that can be adjusted according to your needs. These settings are available as of PostHog 1.33.0 , if you're running an older version, settings can only be set using Environment variables . Instance settings can be managed by staff users by visiting the Instance settings page ( /instance/settings ). Some setting configurations cannot be managed this way, and in particular, settings that determine how PostHog should behave at…

Read next article

PostHog.com doesn't use third party cookies - only a single in-house cookie.

No data is sent to a third party.

Ursula von der Leyen, President of the European Commission