Plausible.io Self-host Setup

Plausible Logo

For my personal website (with virtually no visitors) I was using Google Analytics, just because it was easy. But as soon as I found out about Plausible I decided to give it a go, especially since it’s possible to self-host Plausible. My goal was to setup Plausible in combination with Clickhouse (the click DB), Postgres (already running) behind my Traefik proxy, hosted as a service on Docker Swarm (but locked to a host since I don’t have persistent storage across hosts).

What took time for me to figure out was the DB setup as well as the Traefik setup to host the setup behind my proxy. I did the DB setup manually by “docker run” the commands I found in the Docker Compose file to setup the DB and ClickHouse (see below).

When Plausible itself was running and starting up with no further errors, getting it to run behind my Traefik setup was the next step. I’ll post the complete service startup for my Plausible setup, which includes the Traefik labels to configure the service (no static config file is used here):

docker service create -d -p <pick a free port>:8000 \
--constraint node.hostname==<lock_to_a_host> --name="plausible" \
--mount type=volume,source=geoip,destination=/geoip \
-e "GEOLITE2_COUNTRY_DB=/geoip/GeoLite2-Country.mmdb" \
-e "ADMIN_USER_EMAIL=<your e-mail>" \
-e "ADMIN_USER_NAME=<your admin username>" \
-e "ADMIN_USER_PWD=<your pwd>" \
-e "DATABASE_URL=postgres://<your DB URL including user/pwd/db>" \
-e "CLICKHOUSE_DATABASE_URL=http://<clickhouse host/IP>/<clickhouse DB name>" \
-e "BASE_URL=https://<your plausible hostname incl domain>" \
-e "SECRET_KEY_BASE=<some random string, see plausible manual to create>" \
--label traefik.enable=true \
--label traefik.http.routers.plausible.rule=Host\(\`<your plausible hostname>\`\) \
--label traefik.http.routers.plausible.entrypoints=web-secure \
--label traefik.http.routers.plausible.service=plausible \
--label traefik.http.routers.plausible.tls=true \
--label traefik.http.routers.plausible.tls.certresolver=edge \
--label traefik.http.services.plausible.loadbalancer.server.port=8000 \
--label traefik.http.services.plausible.loadbalancer.passhostheader=true \
--label traefik.docker.network=edge \
--network edge \
plausible/analytics

The way I created the DB, initiated it, etc etc (see the Docker Compose file for all commands):

docker run -e "ADMIN_USER_EMAIL=<your e-mail>" \
-e "ADMIN_USER_NAME=<admin username>" \
-e "ADMIN_USER_PWD=<password>" \
-e "DATABASE_URL=postgres://<your DB URL including user/pwd/db>" \
-e "CLICKHOUSE_DATABASE_URL=http://<clickhouse host/IP>/<clickhouse DB name>" \
-e "BASE_URL=https://<your plausible hostname incl domain>" \
-e "SECRET_KEY_BASE=<some random string, see plausible manual to create>" \
plausible/analytics /entrypoint.sh db createdb

followed by the same command but ending in:

db migratedb
init-admin

After these steps, combined with the Plausible manual I got the local service running.

For completeness sake I’ll also post my startup for the ClickHouse container, which is not a service but a stand-alone container:

docker run -d -p <local port>:8123 -p <local port>:9000 \
--restart=unless-stopped \
-v /etc/localtime:/etc/localtime:ro \
--ulimit nofile=262144:262144 \
--name="clickhouse" \
--network edge \
-v /<local path for persistent data>/data:/var/lib/clickhouse \
-v /<local path for persistent data>/clickhouse-config.xml:/etc/clickhouse-server/config.d/logging.xml:ro \
-v /<local path for persistent data>/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/logging.xml:ro \
yandex/clickhouse-server:21.3.2.5

To update the image of Plausible, running as a service:

docker service update --image plausible/analytics plausibe

Then, since I use Netlify, I just create a post-processing add-on to inject the tracking code into the HEAD section and there we go: self-hosted, privacy respecting web analytics!