Self-host Plausible Analytics (Community Edition) with Docker

Install Plausible Community Edition with its official Docker Compose setup, serve it over HTTPS with Caddy, add your site, and back up and upgrade it.

Tested on Ubuntu 24.04 LTS

Before you start

  • A server with at least 2 GB of memory and Docker Engine with the Compose plugin
  • A subdomain for the dashboard
  • Root or a user with sudo
  • Git

To self-host Plausible Analytics, clone the official plausible/community-edition repository at a release tag, put your domain and a secret key in its .env file, and start it with docker compose up -d. You then either let Plausible get its own Let's Encrypt certificate on ports 80 and 443, or, as here, bind it to 127.0.0.1:8000 and put Caddy in front so it can share the server with other sites.

Plausible Community Edition (CE) is the free, self-hosted release of Plausible, licensed under the AGPL-3.0. It is three containers: the Plausible app, PostgreSQL for accounts and settings, and ClickHouse for the visitor events. This tutorial uses CE v3.2.1, the newest release at the time of writing.

What In this tutorial
The dashboard's domain plausible.example.com
The site you measure www.example.com
The server's public IPv4 address 203.0.113.10
The install directory /opt/plausible-ce

Check that CE is right for you

Plausible's own comparison is candid about the differences from their paid cloud service:

Plausible Cloud Plausible CE (self-hosted)
Cost Subscription Free; you pay for the server
Running it Done for you Installs, upgrades, backups, uptime and security are yours
Releases Continuous About twice a year
Not included in CE Marketing funnels, user journeys, ecommerce revenue goals, SSO, the Sites API
Bot filtering Includes excluding data center IP ranges Basic: user agents and referrer spam
Support Premium support Community only

Your visitor data stays on your server, in the country you choose. The tracking script and the dashboard are the same as in the cloud version.

Check the server can run ClickHouse

The CE README lists two requirements:

  • A CPU with SSE 4.2 (or NEON on ARM). ClickHouse won't start without it. Every current x86 server CPU has it; check with:

    bash
    grep -m1 -o sse4_2 /proc/cpuinfo

    It prints sse4_2. No output means ClickHouse can't run on this CPU.

  • At least 2 GB of memory is recommended, so ClickHouse and Plausible don't run out. The repository already ships settings that make ClickHouse use less memory on small servers.

Download the release and configure it

Clone the repository at the release tag, so you get the Compose file that matches that version:

bash
cd /opt
sudo git clone -b v3.2.1 --single-branch https://github.com/plausible/community-edition plausible-ce
cd plausible-ce

Write .env with the dashboard's public address, a random secret of the length Plausible requires, and the port it should listen on behind Caddy:

bash
sudo tee .env > /dev/null <<EOF
BASE_URL=https://plausible.example.com
SECRET_KEY_BASE=$(openssl rand -base64 48)
HTTP_PORT=8000
EOF
sudo chmod 600 .env
  • BASE_URL must be the real address people will use; Plausible uses it in links and to check websocket connections.
  • SECRET_KEY_BASE signs sessions and derives other keys. Keep it secret and back it up: changing it logs everyone out and makes saved two-factor secrets unreadable.
  • HTTP_PORT=8000 makes Plausible listen on plain HTTP for Caddy. If you set HTTP_PORT=80 and HTTPS_PORT=443 instead and publish those ports, Plausible gets its own certificate and needs no proxy, but then nothing else on the server can use ports 80 and 443.

Publish the port on localhost only with a compose.override.yml, which Compose merges with the official file, so upgrades don't overwrite your change:

bash
sudo tee compose.override.yml > /dev/null <<'EOF'
services:
  plausible:
    ports:
      - 127.0.0.1:8000:${HTTP_PORT}
EOF

Binding to 127.0.0.1 matters: Docker's published ports bypass ufw, so a bare 8000:8000 would be reachable from the internet.

Start it

bash
sudo docker compose up -d

The first start downloads the images and creates the databases. ClickHouse and PostgreSQL report healthy first, then Plausible starts.

Check it worked

bash
sudo docker compose ps
curl -s http://127.0.0.1:8000/api/health

All three services are up and the databases (healthy), and the health check prints {"sessions":"ok","postgres":"ok","clickhouse":"ok","sites_cache":"ok"}.

Put Caddy in front for HTTPS

Point an A record (and AAAA, if the server has IPv6) for plausible.example.com at the server, open the web ports, and install Caddy from its repository:

bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy

Replace /etc/caddy/Caddyfile with:

text
plausible.example.com {
	reverse_proxy 127.0.0.1:8000
}
bash
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Caddy passes the visitor's address in X-Forwarded-For and handles the websocket for the live view, which is all Plausible's reverse proxy guide asks for.

Create your account and add the site

  1. Open https://plausible.example.com straight away. It redirects to the registration page; the first account you register becomes the owner.
  2. Register now, before anyone else finds the page. After the first account, CE only lets invited people register (DISABLE_REGISTRATION defaults to invite_only). To close registration completely, add DISABLE_REGISTRATION=true to .env and run sudo docker compose up -d.
  3. Add your site (www.example.com). Plausible shows the tracking snippet for it.
  4. Paste the snippet into the <head> of every page on your site, exactly as shown. It loads the script from https://plausible.example.com.

Check it worked

Open your site in a browser with ad blocking turned off, then look at the site's dashboard in Plausible: the visit appears in the live visitor count within a few seconds. Content blockers that block analytics also block self-hosted Plausible, so some visits are never counted.

Without email settings, Plausible can't send invitations, password resets or reports. Configure SMTP in .env with the SMTP_HOST_ADDR, SMTP_HOST_PORT, SMTP_USER_NAME, SMTP_USER_PWD and MAILER_EMAIL variables from the configuration page, then run sudo docker compose up -d.

Back it up

Your data lives in three volumes: plausible-ce_db-data (PostgreSQL: accounts, sites, goals), plausible-ce_event-data (ClickHouse: all the visits) and plausible-ce_plausible-data. The simplest consistent backup stops the stack for the time it takes to copy them; visits sent during those seconds are lost:

bash
cd /opt/plausible-ce
sudo docker compose stop
sudo docker run --rm \
  -v plausible-ce_db-data:/db-data:ro \
  -v plausible-ce_event-data:/event-data:ro \
  -v plausible-ce_plausible-data:/plausible-data:ro \
  -v /root:/backup alpine \
  tar czf /backup/plausible-$(date +%F).tgz /db-data /event-data /plausible-data
sudo docker compose start

Keep .env with it: without the same SECRET_KEY_BASE, a restore can't read what was encrypted with it. Copy the archive off the server; Back up your server shows how to do it nightly.

Upgrade

Plausible doesn't backport fixes, so stay current. Watch the releases and read each release's upgrade notes first, since major versions can need extra steps. The repository has one branch per release, named after the version. For a normal upgrade, back up, then pull the new release's branch into your copy and recreate the containers. Replace vX.Y.Z with the release you're moving to:

bash
cd /opt/plausible-ce
sudo git pull origin vX.Y.Z
grep image: compose.yml
sudo docker compose up -d

grep shows the image tags you're about to run. Your .env and compose.override.yml aren't part of the repository, so they stay as they are. Moving from the v3.2.0 branch to v3.2.1 this way is a plain fast-forward. The upgrade guide has the details.

Troubleshooting

ClickHouse keeps restarting and its log mentions SSE 4.2. The CPU lacks the instruction set ClickHouse needs. Check grep sse4_2 /proc/cpuinfo; a server without it can't run Plausible CE.

Containers are killed or restart under load. The server is out of memory. dmesg | grep -i oom shows the kernel killing a process. Move to a server with more memory; 2 GB is the floor, not a comfortable size for busy sites.

The dashboard loads but live visitors never update, or the browser console shows a websocket error. BASE_URL doesn't match the address in the browser, or the proxy doesn't pass websockets (Caddy does by default; with nginx, add the /live/websocket block from Plausible's guide).

Every visit shows the same country, or none at all. Plausible sees Caddy's address instead of the visitor's. Proxy with Caddy's reverse_proxy as above, which sends X-Forwarded-For. CE uses a free country-level geolocation database unless you add a MaxMind key for city-level data.

Caddy logs could not get certificate from issuer. DNS doesn't point at this server yet, or ports 80 and 443 are closed in ufw or a firewall in front of the server.

Next steps

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.

  • One email, on launch day
  • Monthly or yearly, no lock-in
  • 14-day money-back guarantee