# 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.

Source: https://vpsnine.com/tutorials/self-host-plausible-analytics · Updated: 2026-10-21

Difficulty: intermediate · Time: about 30 minutes · Tested on: Ubuntu 24.04 LTS

Prerequisites:

- 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](https://github.com/plausible/analytics/blob/master/LICENSE.md). 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](https://plausible.io/self-hosted-web-analytics) 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](https://github.com/plausible/community-edition) 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](https://github.com/plausible/community-edition/wiki/Reverse-Proxy) 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](https://github.com/plausible/community-edition/wiki/Configuration), 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](https://vpsnine.com/help/backups-you-should-run) shows how to do it nightly.

## Upgrade

Plausible doesn't backport fixes, so stay current. Watch the [releases](https://github.com/plausible/analytics/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](https://github.com/plausible/community-edition/wiki/Upgrade) 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](https://vpsnine.com/tutorials/self-host-uptime-kuma).
- Run more containers behind the same proxy with [Docker Compose and a reverse proxy](https://vpsnine.com/tutorials/docker-compose-reverse-proxy).
- Read the [CE wiki](https://github.com/plausible/community-edition/wiki) for email, Google Search Console and geolocation settings.
