Plausible Analytics is a privacy-friendly alternative to Google Analytics — no cookie banner required, GDPR-compliant, and you can run it yourself. Version 3 ships a completely rewritten frontend built on Phoenix LiveView, and that changes a few things nobody wrote down.
Here are the four problems I ran into during setup.
TL;DR
| Problem | Symptom | Fix |
|---|---|---|
| ClickHouse 24.12: user-level settings rejected | Container refuses to start | Remove user-level settings from the XML |
| ClickHouse default user has no network access | CLICKHOUSE_DATABASE_URL fails | Set the CLICKHOUSE_PASSWORD env var |
docker compose restart does not re-read env_file | Env changes have no effect | Use docker compose up -d instead of restart |
| Phoenix LiveView needs WebSocket | Login button does nothing | Add location /live/websocket to nginx |
Pitfall 1: ClickHouse 24.12 rejects user-level settings
The official Plausible docs suggest running ClickHouse with a low-resources.xml on smaller servers. Older versions of that config carried settings such as max_bytes_before_external_group_by or max_bytes_before_external_sort. As of ClickHouse 24.12, those settings are no longer allowed in user profiles.
Symptom: the ClickHouse container never comes up. From the logs:
Exception: Setting max_bytes_before_external_group_by is not allowed in user profiles.
Fix: drop those settings from the XML. A low-resources.xml that works with ClickHouse 24.12 looks like this:
<clickhouse>
<max_concurrent_queries>10</max_concurrent_queries>
<max_server_memory_usage_to_ram_ratio>0.4</max_server_memory_usage_to_ram_ratio>
<mark_cache_size>536870912</mark_cache_size>
</clickhouse>
Pitfall 2: the ClickHouse default user has no network access
After fixing pitfall 1, ClickHouse starts — and Plausible still cannot connect. Without an explicit password, the default user in ClickHouse 24.12 gets no network access at all.
Symptom: Plausible boots, but every event request fails. From the logs:
[error] Clickhouse.Error: Code: 516. DB::Exception: default: Authentication failed
Fix: set the CLICKHOUSE_PASSWORD environment variable in your compose.yml:
plausible_events_db:
image: clickhouse/clickhouse-server:24.12-alpine
environment:
- CLICKHOUSE_PASSWORD=your-secure-password
And match it in the Plausible configuration:
CLICKHOUSE_DATABASE_URL=http://default:your-secure-password@plausible_events_db:8123/plausible_events
Pitfall 3: docker compose restart does not re-read env_file
Change something in .env or plausible-conf.env, run docker compose restart, and nothing happens. The container restarts, but the environment variables still come from the existing container state.
Symptom: edits to DISABLE_REGISTRATION, SECRET_KEY_BASE or database URLs have no effect after docker compose restart.
This bites hardest during first-time setup, where it creates a chicken-and-egg problem: DISABLE_REGISTRATION=invite_only blocks you from creating the very first account. You flip it to false — and restart never picks the change up.
Fix: use docker compose up -d instead of restart:
# WRONG: container restarts, env_file is NOT re-read
docker compose restart
# RIGHT: container is recreated, env_file is re-read
docker compose up -d
up -d detects changes to compose.yml and env_file and recreates only the affected containers. restart deliberately does not, and Docker documents it: “If you make changes to your compose.yml configuration, these changes are not reflected after running this command. For example, changes to environment variables […] are not updated after restarting.” By design, not a bug.
Pitfall 4: Phoenix LiveView needs WebSocket in nginx
Plausible v3 was rewritten on Elixir/Phoenix and drives its interactive frontend through Phoenix LiveView. LiveView talks over WebSockets rather than plain HTTP requests.
Symptom: the Plausible dashboard is reachable, the login page renders — and clicking “Login” or “Create Account” does nothing. No HTTP error, no redirect, just silence. Browser DevTools shows a failed WebSocket attempt against /live/websocket.
Fix: proxy /live/websocket explicitly, with the WebSocket upgrade headers:
server {
listen 443 ssl http2;
server_name stats.example.com;
# WebSocket for Phoenix LiveView
location /live/websocket {
proxy_pass http://plausible-backend:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
# everything else
location / {
proxy_pass http://plausible-backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Without the location /live/websocket block, nginx never upgrades the connection, and every form submit in Plausible v3 fails silently.
Verification
# 1. all containers up and healthy?
docker compose ps
# 2. Plausible reachable?
curl -s -o /dev/null -w "%{http_code}" https://stats.example.com
# expected: 200
# 3. send a pageview by hand (in case an ad blocker eats the script)
curl -s -o /dev/null -w "%{http_code}" \
"https://stats.example.com/api/event" \
-H "Content-Type: application/json" \
-d '{"name":"pageview","url":"https://example.com/","domain":"example.com"}'
# expected: 202
Takeaway
Self-hosting Plausible v3 is doable. What makes it slow is the combination of ClickHouse 24.12 breaking changes and the new Phoenix LiveView frontend, neither of which the documentation covers yet.
Two habits save the most time: reach for docker compose up -d instead of restart whenever environment variables change, and check WebSocket support in nginx whenever you put a LiveView app behind a proxy.