Plausible Community Edition is a self-hosted, cookie-free analytics stack. The same product family powers Plausible Cloud, and CE is the free, AGPL-licensed release you run yourself. On October 18, 2026, the analytics repository had about 29,500 stars, and the community-edition compose repo had about 2,900. This guide installs CE v3.2.1 from the official Compose files, pins every image tag, puts the dashboard on 127.0.0.1, and confirms a real pageview on a lab site.
The Umami Docker and PostgreSQL guide covers a lighter Postgres-only stack. Plausible CE adds ClickHouse for events and ships a different feature set from Cloud. For a broader app platform on the same VPS, see the Coolify install guide.
TL;DR:
- Clone
plausible/community-editionat tagv3.2.1, setBASE_URLand a 64-byteSECRET_KEY_BASEin.env, and pin Postgres and ClickHouse to exact tags incompose.override.yml. - Bind the app to
127.0.0.1:8000and put Nginx Proxy Manager or Caddy in front with HTTPS. KeepBASE_URLequal to the public URL. - Open the dashboard, create the first account, add a site, paste the generated script into the site
<head>, and confirm a pageview on the dashboard. - Expect about 2 GB of RAM for a calm ClickHouse setup. CPU needs SSE 4.2 or NEON.
- Upgrade by checking out a newer CE tag and running
docker compose up -d. Back up Postgres withpg_dumpand keep the ClickHouse volumes.
Table of contents
What CE gives you, and what stays on Cloud
Feature and licence differences
The self-hosting docs compare Cloud and CE in one table. The points that matter for a home lab or a small team are:
- You own the server: installs, upgrades, backups, capacity and uptime are yours.
- CE releases twice a year. Cloud ships features continuously.
- Marketing funnels, user journeys, ecommerce revenue goals, SSO and the sites API are Cloud-only.
- Bot filtering on CE is the basic User-Agent and referrer-spam path. Cloud adds data-center IP filtering and a broader bot model.
- Premium human support is Cloud-only. Self-hosting is community-supported only, per the self-hosting docs.
- CE is AGPL-3.0 (or later). Cloud is a paid subscription that funds the project.
If you modify CE and offer it as a network service, AGPL requires you to share the corresponding source with users of that service. Read the licence before you ship a public SaaS on top of CE.
Hardware and CPU requirements
The CE README asks for Docker, Docker Compose, a CPU with SSE 4.2 or NEON (ClickHouse needs it), and at least 2 GB of RAM so ClickHouse and Plausible stay clear of OOM kills. The compose file mounts low-resource ClickHouse settings for small servers. On the lab host used for this guide (8 vCPUs with SSE 4.2, Debian 13), the three containers used about 710 MB of RAM after the first pageviews: about 450 MB for Plausible, 185 MB for ClickHouse and 80 MB for Postgres.
Install the official Compose stack
Clone the repo and set .env
The install path is the community-edition repository, not a hand-rolled compose file. Clone a specific tag so the ClickHouse config files match the app:
git clone -b v3.2.1 --single-branch https://github.com/plausible/community-edition plausible-ce
cd plausible-ce
Create .env with the two required variables from the configuration wiki:
touch .env
chmod 600 .env
echo "BASE_URL=https://plausible.example.com" >> .env
echo "SECRET_KEY_BASE=$(openssl rand -base64 48)" >> .env
echo "HTTP_PORT=8000" >> .env
BASE_URL has no default. It drives link generation and WebSocket origin checks. Set it to the URL people will type in the browser, including https:// once a reverse proxy terminates TLS. For a local evaluation, the README tip is BASE_URL=http://localhost:8000 (or any free port). The lab run used http://127.0.0.1:8000.
SECRET_KEY_BASE also has no default. It must be at least 64 bytes. openssl rand -base64 48 produces a 64-character value that meets that rule. Runtime config raises if the key is missing: SECRET_KEY_BASE configuration option is required. A short key fails later with cookie store expects conn.secret_key_base to be at least 64 bytes, which matches discussion #3516 and issue #5612.
Pin image tags and bind to localhost
Upstream compose.yml at v3.2.1 uses ghcr.io/plausible/community-edition:v3.2.1, postgres:16-alpine and clickhouse/clickhouse-server:24.12-alpine. The last two float. On October 18, 2026, those tags resolved to PostgreSQL 16.15 and ClickHouse 24.12.6.70. Put the exact tags in compose.override.yml so future docker compose pull calls stay on known builds, and publish the app only on the loopback address as the reverse-proxy wiki shows:
services:
plausible_db:
image: postgres:16.15-alpine
plausible_events_db:
image: clickhouse/clickhouse-server:24.12.6.70-alpine
plausible:
image: ghcr.io/plausible/community-edition:v3.2.1
ports:
- "127.0.0.1:8000:8000"
The override file is the supported place for local changes. It survives git pull of a new CE tag better than editing compose.yml.
The stack looks like this once it is up:
Start it:
docker compose up -d
docker compose ps
curl --head http://127.0.0.1:8000
On a warm host with images already pulled, Postgres and ClickHouse became healthy in under a minute, and /register returned HTTP 200 about 15 seconds after the app container started. An Uptime Kuma HTTP monitor on /login is enough to notice when the dashboard stops answering. The first visit is the registration page:
Create that first account right away. Default registration is invite-only after the first user (DISABLE_REGISTRATION defaults to invite_only in the wiki). The first account owns the instance.
Default database credentials in the compose file are postgres / postgres. Change them for anything exposed beyond a private lab by setting POSTGRES_PASSWORD and a matching DATABASE_URL in .env (see the configuration wiki).
Put HTTPS in front
Reverse proxy layout
From CE 2.1.2 onward, Plausible can request Let's Encrypt certificates itself when HTTP_PORT=80 and HTTPS_PORT=443 are published. Behind an existing proxy, keep HTTP_PORT=8000, bind 127.0.0.1:8000, and terminate TLS on the proxy. That is the layout this guide tested.
A minimal Caddy config from the wiki is:
plausible.example.com {
reverse_proxy localhost:8000
}
Nginx Proxy Manager works the same way: proxy host to http://127.0.0.1:8000, force SSL, and enable WebSockets so /live/websocket stays up for the live dashboard. The same 127.0.0.1 binding pattern shows up in the Vaultwarden HTTPS guide and the Paperless-ngx Compose guide. The wiki's Nginx sample proxies that path with Upgrade and Connection headers.
Keep BASE_URL on the public hostname
Whatever you pick, BASE_URL must match the public URL. With a wrong host, the dashboard HTML can load while the LiveView WebSocket returns 403. Issue #205 shows the log line Could not check origin for Phoenix.Socket transport when the browser origin and BASE_URL disagree. After you change .env, run docker compose up -d so the container recreates. A plain docker compose restart does not reload env vars.
Add a site and confirm a pageview
Install the tracking script
After registration, the wizard asks for a domain and timezone, then shows a site-specific script. Paste it into the <head> of the site. On CE v3.2.1 the snippet looks like this shape (the pa-… filename is unique per site):
<!-- Privacy-friendly analytics by Plausible -->
<script async src="https://plausible.example.com/js/pa-xxxxxxxx.js"></script>
<script>
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
plausible.init()
</script>
Optional checkboxes turn on outbound-link, file-download and form-submission measurements. The new script updates those choices from the dashboard. Legacy snippets that used data-domain still work. The script update guide covers migration.
The script's event endpoint is taken from BASE_URL (it posts to {BASE_URL}/api/event). Sites that only allowlist their own analytics host in Content-Security-Policy need that origin in connect-src, or an endpoint override in plausible.init as shown in discussion #6126.
Confirm the first pageview
Open the site in a normal browser and watch the CE dashboard for the domain. The lab run added example.test, served a static page with the generated snippet, and recorded pageviews. After four accepted events, the dashboard showed 4 unique visitors, 4 total pageviews and the / path under Top pages:
Two checks that catch false starts:
- The script ignores localhost and
127.0.0.1by design. The browser console printsIgnoring Event: localhost. That matches community-edition issue #92 and the troubleshooting docs. Test on a real hostname (a/etc/hostsentry is enough in a lab). - A 202 from
POST /api/eventis not always a stored event. The troubleshooting docs say to look forx-plausible-dropped: 1when a visit is filtered. The lab posts that used a normal browser User-Agent and anX-Forwarded-Foraddress returned 202 without that header, and ClickHouse held four rows inplausible_events_db.events_v2.
Upgrades and backups
Upgrades
The upgrade wiki recommends pinning a full patch tag such as v3.2.1. Security fixes are not backported, so plan to move forward. v3.2.1 itself is a security release that removes an exposed /storybook endpoint (CVE-2026-8467). General steps for a patch or minor bump:
cd plausible-ce
git fetch origin v3.2.1:v3.2.1
git checkout v3.2.1
# keep your .env and compose.override.yml
docker compose up -d
Read the release notes before every major bump. Some releases change ClickHouse config files in the community-edition repo, which is why the checkout step matters.
Backups
Postgres holds users and site settings. ClickHouse holds events. The Upgrade PostgreSQL wiki shows a pg_dump path that doubles as a backup:
docker compose stop plausible
docker compose exec plausible_db sh -c "pg_dump -U postgres plausible_db > plausible_db.bak"
docker compose cp plausible_db:plausible_db.bak ./plausible_db.bak
docker compose start plausible
Keep copies of the ClickHouse volumes (event-data, and event-logs if you care about server logs) with your volume backup tool. There is no separate CE wiki page that ships a one-line ClickHouse dump. Restoring across major ClickHouse versions needs extra care, so keep the image tag pin in compose.override.yml.
Also back up .env. Losing SECRET_KEY_BASE logs everyone out of the dashboard. Site data in Postgres and ClickHouse stays, as ruslandoga noted when rotating the key.
CE can also send account activation, password resets and optional reports when SMTP or a mail provider adapter is configured. The configuration wiki lists SMTP_HOST_ADDR, MAILER_EMAIL and the Postmark, Mailgun, Mandrill and SendGrid variables. Without SMTP, local accounts still work when ENABLE_EMAIL_VERIFICATION stays at its default false. Those providers were not exercised in the lab run.
FAQ
Setup and resources
How much RAM does Plausible CE need?
The CE README recommends at least 2 GB so ClickHouse and Plausible avoid OOM kills. The lab stack with the bundled low-resource ClickHouse config used about 710 MB of RAM after the first pageviews. Builds and heavy queries need more headroom than idle stats.
Why does the dashboard load but live data stay empty?
BASE_URL usually does not match the URL in the browser. The HTML can still load while /live/websocket fails origin checks. Set BASE_URL to the public URL, then recreate the container with docker compose up -d. See issue #205.
Why is SECRET_KEY_BASE required, and how long must it be?
The configuration wiki requires it and asks for at least 64 bytes. Generate one with openssl rand -base64 48. A missing key stops startup. A short key breaks cookie sessions with cookie store expects conn.secret_key_base to be at least 64 bytes.
Tracking and HTTPS
Why does the browser say "Ignoring Event: localhost"?
The tracker refuses localhost and loopback hosts so local development noise stays out of production stats. Use a real hostname for the test site, or a hosts-file entry that is not localhost. Maintainer replies in issue #92 call out the same console warning.
Which Cloud features are missing from CE?
Per the self-hosting docs: marketing funnels, user journeys, ecommerce revenue goals, SSO and the sites API. Bot filtering is also simpler on CE, and there is no premium support channel.
How do you put HTTPS in front of CE?
Either publish ports 80 and 443 and let CE request certificates, or bind 127.0.0.1:8000 and terminate TLS on Caddy or Nginx Proxy Manager. Keep BASE_URL on the https:// URL in both cases. The reverse-proxy wiki has sample configs.
Originally published on DeployLark: Self-Host Plausible Community Edition with Docker




Top comments (0)