You Won’t Believe What Happened When I Installed Plausible with Docker

If you're like me , running more than one websites and want's something open-source unlike Google analytics complxity, you've probably looked into Plausible Analytics.
Hosting your own analytics sounds simple– until you see it's not. I went throught every possible Docker and Self-hosting error you can think of: broken databases , 502 bad gateway errors, Docker volumes refusing to die and even accidentally deleting my entire ghost blogs.
What Is Plausible Analytics?
Plausible is a lightweight, open-source and privacy focused alternative to Google Analytics. It's really simple and cookie free.
We want to answer these questions:
- Is Plausible is free?
- Can I self-host it on my server with Docker and Caddy?
- How can i monitor analytics for multiple websites from one dashboard?
If you want to self-hosting your plausible , yes it's free. In this article we'll walk throught step by step processes you should take using Docker , Caddy and custom domains.
During setup, I had to decide between using a subdomain or subdirectory for my websites — something that can affect your configuration and even SEO. I compared the two approaches in Comparison Between them if you’re facing the same decision.
Comparison Between subdomain and subdirectory
What Was My Setup
- Run a multiple container using one docker-compose.yml.
- Subdomains:
- blog.domain.com –> Ghost site
- nomad.domain.com –> Flask app
- plausible.domain.com –> Plausible (self-hosting)
- Use Caddy as reverse proxy for HTTPS and subdomain routing
- Setup everything from one place
My Full Stack Overview
- OS: Ubuntu VPS
- Reverse Proxy: Caddy
- Docker & Docker Compose
- Backend services:
- Ghost blog
- MySQL
- Plausible Analytics
- PostgreSQL
- Clickhouse
Folder Structure
This is my project structure on my server:
.
├── docker-compose.yml
├── Caddyfile
├── tourist/ # Flask app
└── plausible-selfhost/ # Cloned from GitHub
Step-by-Step Setup
- Clone the Plausible Self-Hosting Repo
git clone https://github.com/plausible/hosting plausible-selfhost
cd plausible-selfhost
- Generate a .env file
touch .env
Add the following content and update values:
BASE_URL=https://yourdomain.com
SECRET_KEY_BASE=supersecretkey123
MAILER_EMAIL=hello@domain.com
SMTP_HOST=mail
SMTP_PORT=25
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_FROM_ADDRESS=hello@domain.com
You can generate your own secret key (+32 characters). use this:
openssl rand -base64 32
- Update your docker-compose.yml
Here's the full config with your Ghost,Flask and Caddy services + the new Plausible setup:
version: '3.8'
services:
ghost:
image: ghost:5-alpine
container_name: ghost
restart: unless-stopped
depends_on:
- mysql
environment:
url: https://blog.domain.com
database__client: mysql
database__connection__host: mysql
database__connection__user: ghost
database__connection__password: secret123
database__connection__database: ghostdb
volumes:
- ghost_data:/var/lib/ghost/content
expose:
- 2368
mysql:
image: mysql:8
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: ghostdb
MYSQL_USER: ghost
MYSQL_PASSWORD: secret123
volumes:
- mysql_data:/var/lib/mysql
tourist:
build: ./tourist
container_name: tourist
restart: unless-stopped
expose:
- 5000
volumes:
- ./tourist:/app
environment:
FLASK_ENV: production
command: flask run --host=0.0.0.0 --port=5000
caddy:
image: caddy:alpine
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- caddy_data:/data
- caddy_config:/config
- ./Caddyfile:/etc/caddy/Caddyfile
plausible:
image: plausible/analytics:latest
container_name: plausible
depends_on:
- postgres
- clickhouse
- mail
env_file:
- ./plausible-selfhost/.env
restart: unless-stopped
expose:
- 8000
postgres:
image: postgres:14
container_name: plausible_postgres
restart: unless-stopped
environment:
POSTGRES_DB: plausible
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgrespass
volumes:
- plausible_postgres_data:/var/lib/postgresql/data
clickhouse:
image: clickhouse/clickhouse-server:22.6-alpine
container_name: plausible_clickhouse
restart: unless-stopped
ulimits:
nofile:
soft: 262144
hard: 262144
volumes:
- plausible_clickhouse_data:/var/lib/clickhouse
mail:
image: bytemark/smtp
container_name: plausible_smtp
restart: unless-stopped
volumes:
ghost_data:
mysql_data:
caddy_data:
caddy_config:
plausible_postgres_data:
plausible_clickhouse_data:
- Caddyfile (with Plausible)
blog.domain.com www.blog.domain.com {
reverse_proxy ghost:2368
}
nomad.domain.com www.nomad.domain.com {
reverse_proxy tourist:5000
}
plausible.domain.com {
reverse_proxy plausible:8000
}
- Run Everything
From directory containing docker-compose.yml, run:
docker-compose up -d
Now visit https://plausible.domain.com and create your admin account.
- Add Tracking to Your Site
Add this script in to <head> section of your HTML (Don't forget to replace your Domain):
<script defer data-domain="blog.domain.com" src="https://plausible.domain.com/js/plausible.js"></script>
- You can add more domains inside the Plausible dashbord later.
But I Got Lots Of Errors
- First I ran:
docker ps
- When I tried to cleaning everything with:
docker compose down -v
- But I got this:
! Volume arash_plausible_postgres_data Resource is still in use
! Volume arash_plausible_clickhouse_data Resource is still in use
! Network arash_default Resource is still in use
- How I Fix it:
docker ps -a
docker rm -f <container_name_or_id> # remove all orphaned or stuck containers
docker volume rm <volume_name>
docker network rm <network_name>
Huge Warning: docker-compose down -v Deletes All Data
I didn't realize that this command deletes all Docker Volumes, including database data, when i ran:
docker compose down -v
and suddenly deleted all my Ghost Blog content (posts, media, settings).
Lesson Learned:
Never run docker compose down -v unless you've backed up your volumes.
Backup Ghost Volumes before doing it:
docker run --rm -v ghost_data:/data -v $(pwd):/backup alpine tar czf /backup/ghost_backup.tar.gz -C /data .
Error: 502 Bad Gateway from Caddy
curl -I https://plausible.domain.com
#Returned
HTTP/2 502
Fix:
Caddy couldn't reach plausible:8000 because the container was crashing, make sure plausible container is running:
docker ps | grep plausible
verify caddy can connect to it:
docker exec -it caddy wget http://plausible:8000
Error: plausible Container Crashes Due to Database Errors
Postgrex.Error: password authentication failed for user "postgres"
Fix:
Make sure your docker-compose.yml and .env file match:
.env:
DATABASE_URL=postgres://postgres:postgres@plausible_postgres:5432/plausible
docker-compose.yml:
POSTGRES_PASSWORD: postgres
They must match, Restart again:
docker-compose down
docker-compose up -d --build
Error: Database Doesn’t Exist
FATAL 3D000 (invalid_catalog_name) database "plausible" does not exist
Plausible tries to auto-create the DB, but fails if volumes are messed up.
Fix:
Be sure that container is running with this command:
command: sh -c "/entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
You can manually create the DB inside Postgres:
docker exec -it plausible_postgres psql -U postgres
CREATE DATABASE plausible;
\q
Error: Domain Already Registered in Plausible
This domain cannot be registered. Perhaps one of your colleagues registered it?
Fix:
Log in with original admin user, or manually delete the domain from postgres:
docker exec -it plausible_postgres psql -U postgres
\c plausible
DELETE FROM sites WHERE domain = 'nomad.domain.com';
Key Lessons I Learned
- docker compose down -v —> wipe out everything
- Always Back up named volumes before cleanup
- Use one docker-compose.yml , don't mix multiple stacks
- Caddy's reverse proxy setup is clean and automatic if containers are healthy
- Plausible is picky about domain registration, one domain = one owner
Related Article
✅ Update: I finally got it right!
After nuking my blog the first time, I took a deep breath, tried again, and successfully added Plausible Analytics without deleting the universe.
Want to see how I did it step by step (with screenshots)?

Plausible Web Analytics Dashbord
Final Thoughts
If you're planning to self-host tools lie Plausible , Ghost , Flask app and more , you'll face into problems. This aticle gives you not just the fixes but the things to avoid breaking.
With Docker , Caddy and a few minutes, I had my analytics dashboard running flawlessly
If you’re building indie projects or freelance websites, this is a powerful free tool you can run forever.
You can fuel my next data science deep dive by buying me a coffee ☕!