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:
grep -m1 -o sse4_2 /proc/cpuinfoIt 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:
cd /opt
sudo git clone -b v3.2.1 --single-branch https://github.com/plausible/community-edition plausible-ce
cd plausible-ceWrite .env with the dashboard's public address, a random secret of the length Plausible requires, and the port it should listen on behind Caddy:
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 .envBASE_URLmust be the real address people will use; Plausible uses it in links and to check websocket connections.SECRET_KEY_BASEsigns 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=8000makes Plausible listen on plain HTTP for Caddy. If you setHTTP_PORT=80andHTTPS_PORT=443instead 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:
sudo tee compose.override.yml > /dev/null <<'EOF'
services:
plausible:
ports:
- 127.0.0.1:8000:${HTTP_PORT}
EOFBinding 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
sudo docker compose up -dThe first start downloads the images and creates the databases. ClickHouse and PostgreSQL report healthy first, then Plausible starts.
Check it worked
sudo docker compose ps
curl -s http://127.0.0.1:8000/api/healthAll 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:
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 caddyReplace /etc/caddy/Caddyfile with:
plausible.example.com {
reverse_proxy 127.0.0.1:8000
}sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddyCaddy 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
- Open
https://plausible.example.comstraight away. It redirects to the registration page; the first account you register becomes the owner. - Register now, before anyone else finds the page. After the first account, CE only lets invited people register (
DISABLE_REGISTRATIONdefaults toinvite_only). To close registration completely, addDISABLE_REGISTRATION=trueto.envand runsudo docker compose up -d. - Add your site (
www.example.com). Plausible shows the tracking snippet for it. - Paste the snippet into the
<head>of every page on your site, exactly as shown. It loads the script fromhttps://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:
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 startKeep .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:
cd /opt/plausible-ce
sudo git pull origin vX.Y.Z
grep image: compose.yml
sudo docker compose up -dgrep 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
- Watch the dashboard and your sites from outside with Uptime Kuma.
- Run more containers behind the same proxy with Docker Compose and a reverse proxy.
- Read the CE wiki for email, Google Search Console and geolocation settings.