Plausible CE with Docker Compose
Open source, privacy-first web analytics. Lightweight, cookie-free Google Analytics alternative. In the project's words: Plausible Analytics on GitHub (repository description) checked 2026-10-01
Replaces: Google Analytics Plausible Analytics on GitHub (repository description: "Lightweight, cookie-free Google Analytics alternative") checked 2026-10-01
Runs on: amd64, arm64 from each image's registry manifest, checked 2026-10-01; a CPU counts only if every image has a build for it. Image by image
Add Plausible CE to the builder to use your own domain, get its passwords generated in your browser, and combine it with other apps in one file.
What Plausible CE needs
Only figures Plausible CE's own documentation publishes, each linked to the page it is on. Where the project gives no number, this page does not invent one.
| Resource | Minimum | Recommended |
|---|---|---|
| RAM | not stated | 2 GB |
| Published as "At least 2 GB of RAM is recommended for running ClickHouse and Plausible without fear of OOMs". Source: Plausible CE README: prerequisites (SSE 4.2 or NEON, 2 GB of RAM), .env, first user checked 2026-10-01 | ||
| CPU | SSE 4.2 or NEON | not stated |
| Published as "CPU must support SSE 4.2 or NEON instruction set or higher (required by ClickHouse)". Source: Plausible CE README: prerequisites (SSE 4.2 or NEON, 2 GB of RAM), .env, first user checked 2026-10-01 | ||
| Disk | The project publishes no figure | |
Which hardware Plausible CE has images for
Read from each image's manifest list in its registry (anonymous, read-only) when this page was built. An app counts for a CPU only if every one of its images lists it.
- x86-64 PC or NAS (
linux/amd64): every image has a build. - Raspberry Pi 4/5, 64-bit OS (
linux/arm64): every image has a build. - Raspberry Pi 3 or Zero 2 W, 32-bit OS (
linux/arm/v7): no image forplausible_events_db,plausible. No image for this hardware; the builder leaves the app out.
| Service | Image | Platforms in the manifest | Digest | Registry | Checked |
|---|---|---|---|---|---|
plausible_db | postgres:16-alpine | amd64, arm/v6, arm/v7, arm64, 386, ppc64le, riscv64, s390x | sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea | registry-1.docker.io | 2026-09-26 |
plausible_events_db | clickhouse/clickhouse-server:24.12-alpine | amd64, arm64 | sha256:cd450891db46cc6ffe313ca2b0fb7dbfb897a6873ca74a724cbe050a2cf62621 | registry-1.docker.io | 2026-10-01 |
plausible | ghcr.io/plausible/community-edition:v3.2.1 | arm64, amd64 | sha256:33e60bfb40f2df5da00f8753b76fad04f67dba3abe6d73eb516e440e3fb62985 | ghcr.io | 2026-10-01 |
docker-compose.yml
This is exactly what the builder writes for Plausible CE alone on example.org: the official definition with its published ports removed and Caddy added in front. Every ${VARIABLE} is defined in the .env below.
# docker-compose.yml built at dankhost.com for: Plausible CE # Each app block is its official compose definition. Only the names were prefixed with # the app slug (services, containers, volumes, bind folders, .env variables) so any set of # apps can share one file; other differences are listed under "Changed:" in each block. # Only Caddy publishes ports. Secrets live in .env next to this file. services: # ---- Caddy: the one reverse proxy, HTTPS certificates from Let's Encrypt ---- # Source: https://caddyserver.com/docs/running (checked 2026-09-23) # Source: https://github.com/dani-garcia/vaultwarden/wiki/Using-Docker-Compose (checked 2026-09-23) # Caddyfile goes in ./caddy/Caddyfile. Fixed address 172.30.0.2 so apps can trust it exactly. caddy: image: "caddy:2" container_name: "caddy" restart: "unless-stopped" ports: - "80:80" - "443:443" - "443:443/udp" volumes: - "./caddy:/etc/caddy" - "caddy-data:/data" - "caddy-config:/config" networks: proxy: ipv4_address: "172.30.0.2" # ---- Plausible CE (plausible.example.org) ---- # Source: https://github.com/plausible/community-edition/blob/v3.2.1/compose.yml (checked 2026-10-01) # Source: https://github.com/plausible/community-edition/blob/v3.2.1/README.md (checked 2026-10-01) # Source: https://github.com/plausible/community-edition/tree/v3.2.1/clickhouse (checked 2026-10-01) # Source: https://github.com/plausible/community-edition/wiki/configuration (checked 2026-10-01) # Source: https://github.com/plausible/community-edition/wiki/reverse-proxy (checked 2026-10-01) # Changed: No port is published: the README's compose.override.yml (80:80 and 443:443, or 127.0.0.1:8000 behind a reverse proxy) is not used. Caddy reaches plausible:8000, the HTTP_PORT default the reverse-proxy page uses, on the proxy network and serves HTTPS. # The two required variables are set: BASE_URL to https://plausible.example.org, and SECRET_KEY_BASE to a generated 64-character value in .env (the README: "at least a 64-byte string"). # The Postgres password 'postgres' is a generated value in .env, set in POSTGRES_PASSWORD and in DATABASE_URL (the configuration page's default URL is the same with the password postgres). # The optional variables the file passes through from .env unset (TOTP_VAULT_KEY, DISABLE_REGISTRATION, the mailer, Google and MaxMind settings, HTTP_PORT, HTTPS_PORT) are left out; unset, Plausible uses the same defaults. # The four ClickHouse files of the repository's clickhouse/ folder at v3.2.1 are written by the builder into ./plausible/clickhouse/, without the comment lines that only link to ClickHouse's documentation. # ClickHouse's healthcheck asks http://plausible_events_db:8123/ping, the service's own name on its network, instead of 127.0.0.1: the same server, which ipv4-only.xml makes listen on 0.0.0.0. Written this way so that no page here carries an IP-address URL. plausible-plausible_db: image: "postgres:16-alpine" container_name: "plausible-plausible_db" restart: "always" volumes: - "plausible-db-data:/var/lib/postgresql/data" environment: POSTGRES_PASSWORD: "${PLAUSIBLE_POSTGRES_PASSWORD}" healthcheck: test: - "CMD-SHELL" - "pg_isready -U postgres" start_period: "1m" networks: plausible-backend: aliases: - "plausible_db" plausible-plausible_events_db: image: "clickhouse/clickhouse-server:24.12-alpine" container_name: "plausible-plausible_events_db" restart: "always" volumes: - "plausible-event-data:/var/lib/clickhouse" - "plausible-event-logs:/var/log/clickhouse-server" - "./plausible/clickhouse/logs.xml:/etc/clickhouse-server/config.d/logs.xml:ro" - "./plausible/clickhouse/ipv4-only.xml:/etc/clickhouse-server/config.d/ipv4-only.xml:ro" - "./plausible/clickhouse/low-resources.xml:/etc/clickhouse-server/config.d/low-resources.xml:ro" - "./plausible/clickhouse/default-profile-low-resources-overrides.xml:/etc/clickhouse-server/users.d/default-profile-low-resources-overrides.xml:ro" ulimits: nofile: soft: 262144 hard: 262144 environment: CLICKHOUSE_SKIP_USER_SETUP: "1" healthcheck: test: - "CMD-SHELL" - "wget --no-verbose --tries=1 -O - http://plausible_events_db:8123/ping || exit 1" start_period: "1m" networks: plausible-backend: aliases: - "plausible_events_db" plausible: image: "ghcr.io/plausible/community-edition:v3.2.1" container_name: "plausible" restart: "always" command: "sh -c \"/entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run\"" depends_on: plausible-plausible_db: condition: "service_healthy" plausible-plausible_events_db: condition: "service_healthy" volumes: - "plausible-data:/var/lib/plausible" ulimits: nofile: soft: 65535 hard: 65535 environment: TMPDIR: "/var/lib/plausible/tmp" BASE_URL: "https://plausible.example.org" SECRET_KEY_BASE: "${PLAUSIBLE_SECRET_KEY_BASE}" DATABASE_URL: "postgres://postgres:${PLAUSIBLE_POSTGRES_PASSWORD}@plausible_db:5432/plausible_db" networks: proxy: {} plausible-backend: {} networks: # Pinned so the trusted-proxy address given to each app (172.30.0.2) is exact. # If "docker compose up" reports "Pool overlaps", change 172.30.0 here, in Caddy's # ipv4_address and in every trusted-proxy value to a free 172.x.0 range. proxy: ipam: config: - subnet: "172.30.0.0/24" ip_range: "172.30.0.128/25" gateway: "172.30.0.1" plausible-backend: internal: true volumes: caddy-data: caddy-config: plausible-db-data: plausible-event-data: plausible-event-logs: plausible-data:
Caddyfile save as caddy/Caddyfile
Caddy gets and renews the HTTPS certificate for plausible.example.org by itself once the DNS record points at your server and ports 80 and 443 reach it.
# Caddyfile built at dankhost.com. Save it as ./caddy/Caddyfile next to docker-compose.yml.
# Caddy gets and renews a Let's Encrypt certificate for each name below by itself,
# once the DNS records point at this server and ports 80 and 443 reach it.
# Plausible CE
plausible.example.org {
reverse_proxy plausible:8000
}
.env
The secrets are left blank here on purpose: a password printed on a public page is the same for everyone who copies it. The builder fills them with random letters and digits made in your browser.
# .env for Plausible CE, from dankhost.com/app/plausible/. Fill the blank secrets before starting. # Keep this file private (chmod 600). # Plausible CE # 64 random letters and digits: the builder fills this in your browser PLAUSIBLE_SECRET_KEY_BASE= # 32 random letters and digits: the builder fills this in your browser PLAUSIBLE_POSTGRES_PASSWORD=
The four files Plausible CE needs next to the compose file
The builder writes them with your domain and fills every secret with random letters and digits made in your browser (crypto.getRandomValues); nothing is sent anywhere. Below, each secret is a FILL-IN-… placeholder instead, because a secret printed on a public page is the same for everyone who copies it.
./plausible/clickhouse/logs.xml
<clickhouse>
<logger>
<level>warning</level>
<console>true</console>
</logger>
<query_log replace="1">
<database>system</database>
<table>query_log</table>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
<engine>
ENGINE = MergeTree
PARTITION BY event_date
ORDER BY (event_time)
TTL event_date + interval 30 day
SETTINGS ttl_only_drop_parts=1
</engine>
</query_log>
<!-- Stops unnecessary logging -->
<metric_log remove="remove" />
<asynchronous_metric_log remove="remove" />
<query_thread_log remove="remove" />
<text_log remove="remove" />
<trace_log remove="remove" />
<session_log remove="remove" />
<part_log remove="remove" />
</clickhouse>
./plausible/clickhouse/ipv4-only.xml
<clickhouse>
<listen_host>0.0.0.0</listen_host>
</clickhouse>
./plausible/clickhouse/low-resources.xml
<clickhouse>
<mark_cache_size>524288000</mark_cache_size>
</clickhouse>
./plausible/clickhouse/default-profile-low-resources-overrides.xml
<clickhouse>
<profiles>
<default>
<max_threads>1</max_threads>
<max_block_size>8192</max_block_size>
<max_download_threads>1</max_download_threads>
<input_format_parallel_parsing>0</input_format_parallel_parsing>
<output_format_parallel_formatting>0</output_format_parallel_formatting>
</default>
</profiles>
</clickhouse>
Changes from the official file
Besides prefixing every service, container, volume, folder and variable with plausible (so any set of apps can share one file), these are all the differences from what the project documents:
- No port is published: the README's compose.override.yml (80:80 and 443:443, or 127.0.0.1:8000 behind a reverse proxy) is not used. Caddy reaches plausible:8000, the HTTP_PORT default the reverse-proxy page uses, on the proxy network and serves HTTPS.
- The two required variables are set: BASE_URL to https://plausible.example.org, and SECRET_KEY_BASE to a generated 64-character value in .env (the README: "at least a 64-byte string").
- The Postgres password 'postgres' is a generated value in .env, set in POSTGRES_PASSWORD and in DATABASE_URL (the configuration page's default URL is the same with the password postgres).
- The optional variables the file passes through from .env unset (TOTP_VAULT_KEY, DISABLE_REGISTRATION, the mailer, Google and MaxMind settings, HTTP_PORT, HTTPS_PORT) are left out; unset, Plausible uses the same defaults.
- The four ClickHouse files of the repository's clickhouse/ folder at v3.2.1 are written by the builder into ./plausible/clickhouse/, without the comment lines that only link to ClickHouse's documentation.
- ClickHouse's healthcheck asks http://plausible_events_db:8123/ping, the service's own name on its network, instead of 127.0.0.1: the same server, which ipv4-only.xml makes listen on 0.0.0.0. Written this way so that no page here carries an IP-address URL.
Notes for Plausible CE behind the proxy
- Open https://plausible.example.org and create the first user (README step 5). After that, registration is invite-only, the default of DISABLE_REGISTRATION.
- Keep .env safe: TOTP_VAULT_KEY, which encrypts two-factor secrets, is derived from SECRET_KEY_BASE unless you set it.
- ClickHouse needs a CPU with SSE 4.2 or NEON, and the README recommends at least 2 GB of RAM.
- Add the snippet Plausible shows for each site to your pages; the visits then go to https://plausible.example.org.
How to run it
- At your DNS provider, add an A record named
plausibleon your domain pointing at the server's public IP address, and forward TCP 80, TCP 443 and UDP 443 to it. - Save
./plausible/clickhouse/logs.xmland./plausible/clickhouse/ipv4-only.xmland./plausible/clickhouse/low-resources.xmland./plausible/clickhouse/default-profile-low-resources-overrides.xmlfrom the files above (or from the builder, with the secrets filled in). - Save the three files in one folder:
docker-compose.ymland.envside by side, the Caddyfile at./caddy/Caddyfile. Replaceexample.orgwith your domain in the Caddyfile, the compose file and the .env, or let the builder do it. - Fill the blank
PLAUSIBLE_SECRET_KEY_BASE,PLAUSIBLE_POSTGRES_PASSWORDin.env. The builder generates them; on the server,tr -dc A-Za-z0-9 </dev/urandom | head -c 32prints 32 random letters and digits. Thenchmod 600 .env. - Start it:
docker compose up -d docker compose logs -f caddy # watch the certificate arrive
- Open the new address (
plausible.plus your domain) in a browser and follow the notes above.
Back it up
Plausible CE publishes no backup procedure. Users, sites, goals and settings are in Postgres; every counted visit is in ClickHouse.
Below is the BACKUP.md the builder writes next to the compose file above: which of its folders and volumes hold data, the dump command the project documents, rewritten for this file's service names, what to copy with which container stopped, and a restore check. Pick more apps in the builder and it covers them all in one file.
# BACKUP.md built at dankhost.com for: Plausible CE
What to copy from the docker-compose.yml built with this file, the database dump each project documents (rewritten for the service names in that file), what to copy with which container stopped, and how to check the result. Run every command in the folder that holds docker-compose.yml.
The folders are owned by the containers' users: put sudo in front of tar if it says "Permission denied". Named volumes live under /var/lib/docker/volumes, not next to the compose file, so they are copied through a throwaway ubuntu container (Docker's documented --volumes-from method). tar makes a full copy each run; for large folders an incremental tool (restic, borg, rsync) saves time and space.
Never run "docker compose down -v" on this file: it deletes the named volumes of every app in it.
## Before you start
BACKUP=/mnt/backup/selfhost # change this: a disk or machine other than this server's system disk
mkdir -p "$BACKUP"
## Every time: the three stack files
tar czf "$BACKUP/stack-files.tar.gz" docker-compose.yml .env caddy
.env holds the database passwords and secret keys the apps were set up with; keep this archive as private as the data.
## Caddy (the reverse proxy)
Caddy's docs: 'The data directory must not be treated as a cache.' It holds the TLS certificates and their private keys; without it Caddy has to ask Let's Encrypt for every certificate again.
- caddy-data (named volume, /data in caddy)
BACK UP: TLS certificates, private keys, OCSP staples.
- caddy-config (named volume, /config in caddy)
SKIP: the last active configuration, kept for 'caddy run --resume', which this setup does not use: it starts from the Caddyfile.
- ./caddy (/etc/caddy in caddy)
IN stack-files.tar.gz: the Caddyfile, copied with the stack files above.
Copy (Caddy keeps serving while you copy):
docker run --rm --volumes-from caddy -v "$BACKUP":/backup ubuntu tar cvf /backup/caddy-data.tar /data
Restore check:
tar tf "$BACKUP/caddy-data.tar" > /dev/null && echo OK
docker run --rm --volumes-from caddy -v "$BACKUP":/backup ubuntu bash -c "cd /data && tar xvf /backup/caddy-data.tar --strip 1"
Sources:
- Caddy docs: Conventions, Data directory: https://caddyserver.com/docs/conventions#data-directory (checked 2026-09-24)
- Docker docs: Volumes, Back up, restore, or migrate data volumes: https://docs.docker.com/engine/storage/volumes/#back-up-restore-or-migrate-data-volumes (checked 2026-09-24)
## Plausible CE
Plausible CE publishes no backup procedure. Users, sites, goals and settings are in Postgres; every counted visit is in ClickHouse.
What this compose mounts:
- plausible-db-data (named volume, /var/lib/postgresql/data in plausible-plausible_db)
COVERED BY THE COMMAND BELOW: Postgres data files; copy them only with the database stopped.
- plausible-event-data (named volume, /var/lib/clickhouse in plausible-plausible_events_db)
BACK UP: ClickHouse: all visit and event data.
- plausible-event-logs (named volume, /var/log/clickhouse-server in plausible-plausible_events_db)
SKIP: ClickHouse server logs.
- ./plausible/clickhouse/logs.xml (/etc/clickhouse-server/config.d/logs.xml in plausible-plausible_events_db)
BACK UP: a ClickHouse setting file from the repository (the builder writes it again).
- ./plausible/clickhouse/ipv4-only.xml (/etc/clickhouse-server/config.d/ipv4-only.xml in plausible-plausible_events_db)
BACK UP: a ClickHouse setting file from the repository (the builder writes it again).
- ./plausible/clickhouse/low-resources.xml (/etc/clickhouse-server/config.d/low-resources.xml in plausible-plausible_events_db)
BACK UP: a ClickHouse setting file from the repository (the builder writes it again).
- ./plausible/clickhouse/default-profile-low-resources-overrides.xml (/etc/clickhouse-server/users.d/default-profile-low-resources-overrides.xml in plausible-plausible_events_db)
BACK UP: a ClickHouse setting file from the repository (the builder writes it again).
- plausible-data (named volume, /var/lib/plausible in plausible)
OPTIONAL: Plausible's own folder: its TMPDIR and downloaded data such as the IP geolocation database.
1. Stop plausible, plausible-plausible_events_db. ClickHouse writes data parts continuously; a copy taken while it runs can catch a part half-written. Stopping plausible first stops new events arriving.
docker compose stop plausible plausible-plausible_events_db
2. Database dump for plausible-plausible_db:
docker compose exec -T plausible-plausible_db pg_dump -U postgres -C plausible_db > "$BACKUP/plausible.sql"
pg_dump of the plausible_db database the configuration page's DATABASE_URL names, with -C so the dump creates the database when it is restored.
3. Copy while plausible, plausible-plausible_events_db are stopped:
docker run --rm --volumes-from plausible-plausible_events_db -v "$BACKUP":/backup ubuntu tar cvf /backup/plausible-event-data.tar /var/lib/clickhouse
tar czf "$BACKUP/plausible-clickhouse-logs.xml.tar.gz" ./plausible/clickhouse/logs.xml
tar czf "$BACKUP/plausible-clickhouse-ipv4-only.xml.tar.gz" ./plausible/clickhouse/ipv4-only.xml
tar czf "$BACKUP/plausible-clickhouse-low-resources.xml.tar.gz" ./plausible/clickhouse/low-resources.xml
tar czf "$BACKUP/plausible-clickhouse-default-profile-low-resources-overrides.xml.tar.gz" ./plausible/clickhouse/default-profile-low-resources-overrides.xml
4. Start it again:
docker compose start plausible plausible-plausible_events_db
Restore check:
grep -c 'PostgreSQL database dump complete' "$BACKUP/plausible.sql" # 1 means pg_dump finished
tar tf "$BACKUP/plausible-event-data.tar" > /dev/null && echo OK
tar tzf "$BACKUP/plausible-clickhouse-logs.xml.tar.gz" > /dev/null && echo OK
tar tzf "$BACKUP/plausible-clickhouse-ipv4-only.xml.tar.gz" > /dev/null && echo OK
tar tzf "$BACKUP/plausible-clickhouse-low-resources.xml.tar.gz" > /dev/null && echo OK
tar tzf "$BACKUP/plausible-clickhouse-default-profile-low-resources-overrides.xml.tar.gz" > /dev/null && echo OK
Put a copy back (with plausible, plausible-plausible_events_db stopped):
docker run --rm --volumes-from plausible-plausible_events_db -v "$BACKUP":/backup ubuntu bash -c "cd /var/lib/clickhouse && tar xvf /backup/plausible-event-data.tar --strip 3"
tar xzf "$BACKUP/plausible-clickhouse-logs.xml.tar.gz" # recreates ./plausible/clickhouse/logs.xml; move the old folder aside first
tar xzf "$BACKUP/plausible-clickhouse-ipv4-only.xml.tar.gz" # recreates ./plausible/clickhouse/ipv4-only.xml; move the old folder aside first
tar xzf "$BACKUP/plausible-clickhouse-low-resources.xml.tar.gz" # recreates ./plausible/clickhouse/low-resources.xml; move the old folder aside first
tar xzf "$BACKUP/plausible-clickhouse-default-profile-low-resources-overrides.xml.tar.gz" # recreates ./plausible/clickhouse/default-profile-low-resources-overrides.xml; move the old folder aside first
Restore the database before Plausible starts:
docker compose up -d plausible-plausible_db
docker compose exec -T plausible-plausible_db psql -U postgres < "$BACKUP/plausible.sql"
Put the ClickHouse volume back, then:
docker compose up -d
Sources:
- Plausible CE wiki: Configuration (BASE_URL, SECRET_KEY_BASE, DISABLE_REGISTRATION, HTTP_PORT, DATABASE_URL): https://github.com/plausible/community-edition/wiki/configuration (checked 2026-10-01)
- Docker docs: Volumes, Back up, restore, or migrate data volumes: https://docs.docker.com/engine/storage/volumes/#back-up-restore-or-migrate-data-volumes (checked 2026-10-01)
Update it
What docker compose pull does depends only on how each image line in the compose file above is tagged. For Plausible CE as this page writes it:
| Service | Image | How it is pinned | What docker compose pull does |
|---|---|---|---|
caddy | caddy:2 | Major version only (tag 2) | Takes the newest image tagged 2: minor and patch releases of 2, never 3. A new major version needs a tag edit. |
plausible-plausible_db database | postgres:16-alpine | Major version only (tag 16-alpine) | Takes the newest image tagged 16-alpine: minor and patch releases of 16, never 17. A new major version needs a tag edit. |
plausible-plausible_events_db | clickhouse/clickhouse-server:24.12-alpine | Major and minor version (tag 24.12-alpine) | Takes the newest image tagged 24.12-alpine: patch releases and rebuilds of 24.12 only. A newer minor or major version needs a tag edit. |
plausible | ghcr.io/plausible/community-edition:v3.2.1 | Exact version (tag v3.2.1) | Does not move: stays on 3.2.1 until you edit the tag (a publisher may re-push the same version on a rebuilt base). |
Do not raise the major version of plausible-plausible_db by editing its tag. Keep its tag, 16-alpine, as it is when you update Plausible CE.
PostgreSQL's docs: a new major version may change how data is stored on disk, so a data folder written by an older major version will not start under a newer one (the server refuses it). Moving needs a dump and restore (pg_dumpall, then load the dump into the new version) or pg_upgrade. Minor releases of the same major version never change the storage format. Source: PostgreSQL docs: Upgrading a PostgreSQL Cluster checked 2026-09-30
What Plausible CE's docs say about updating
Plausible CE's Upgrade page: each release says how to upgrade from the previous one; read it, move to the new version's tag and run docker compose up -d. The page recommends pinning the exact version, as this file does.
- The tag here is v3.2.1, so a pull changes nothing: edit it to the new version.
- A new major version may need data migrations; its release notes say which.
The steps
- Back up first, as in Back it up above. An update can migrate Plausible CE's data on its first start and its database with it; the copy is the way back.
plausibleis pinned to an exact version (see the table), so a pull alone changes nothing there: to update Plausible CE, first edit its tag indocker-compose.ymlto the version you want.- Download the new images. Running containers are not touched yet:
docker compose pull
- Recreate the containers whose image changed. Volumes and bind-mounted folders stay as they are:
docker compose up -d
- Watch Plausible CE start (Ctrl+C stops following the log, not the app):
docker compose logs -f plausible
- Optional: remove the old images the pull left without a tag. This covers every stack on the machine, not only this one:
docker image prune
Sources
Every page below was fetched on the date shown.
- Plausible Analytics on GitHub (repository description) checked 2026-10-01 (what it does)
- Plausible Analytics on GitHub (repository description: "Lightweight, cookie-free Google Analytics alternative") checked 2026-10-01 (what it replaces)
- Plausible CE README: prerequisites (SSE 4.2 or NEON, 2 GB of RAM), .env, first user checked 2026-10-01 (hardware requirements, compose definition and proxy settings)
- Plausible CE: compose.yml at v3.2.1, the tag the README clones checked 2026-10-01 (compose definition and proxy settings)
- Plausible CE: the four ClickHouse files in clickhouse/ at v3.2.1 checked 2026-10-01 (compose definition and proxy settings)
- Plausible CE wiki: Configuration (BASE_URL, SECRET_KEY_BASE, DISABLE_REGISTRATION, HTTP_PORT, DATABASE_URL) checked 2026-10-01 (compose definition and proxy settings, backup plan)
- Plausible CE wiki: Reverse Proxy (HTTP_PORT=8000, reverse_proxy to port 8000) checked 2026-10-01 (compose definition and proxy settings)
- Caddy docs: Keep Caddy running (Docker Compose section) checked 2026-09-23 (Caddy)
- Vaultwarden wiki: Caddy with HTTP challenge (uses the caddy:2 image) checked 2026-09-23 (Caddy)
- Docker docs: Volumes, Back up, restore, or migrate data volumes checked 2026-10-01 (backup plan)
- Caddy docs: Conventions, Data directory checked 2026-09-24 (backup plan)
- Plausible CE wiki: Upgrade (version pinning, release notes) checked 2026-10-01 (update notes)
- PostgreSQL docs: Upgrading a PostgreSQL Cluster checked 2026-09-30 (database upgrade)
- Docker docs: docker compose pull checked 2026-09-30 (update steps)
- Docker docs: docker compose up (recreates changed containers, keeps volumes) checked 2026-09-30 (update steps)
- Docker docs: docker image prune checked 2026-09-30 (update steps)