Self-Host Privacy-First Analytics (Plausible or Umami) on DigitalOcean
Disclosure: Some links in this guide are affiliate links. If you sign up for DigitalOcean through them, ToolsHubKit earns a small commission — at no cost to you.
Google Analytics ships your visitors' data to Google, needs a cookie banner, and buries you in a UI built for enterprises. Self-hosted Plausible or Umami give you a lightweight, cookieless, GDPR-friendly dashboard on infrastructure you control — for the flat cost of a small Droplet. This guide covers both, so you can pick the right one and deploy it with Docker Compose.
Prerequisites:
- Basic Linux comfort (SSH,
sudo) - A domain/subdomain for the analytics dashboard (e.g.
stats.yourdomain.com)
1. Why Ditch Google Analytics
| Google Analytics | Plausible / Umami (self-hosted) | |
|---|---|---|
| Data ownership | Google's servers | Your Droplet |
| Cookies / consent banner | Required | None (cookieless) |
| Script weight | ~45 KB+ | < 2 KB |
| GDPR posture | Complex | Simple (no PII, no cookies) |
| Cost | "Free" (you're the product) | Flat Droplet cost |
| Dashboard | Overwhelming | Single clean page |
2. Plausible vs Umami — Which to Pick
| Plausible | Umami | |
|---|---|---|
| Backend DB | PostgreSQL + ClickHouse | PostgreSQL or MySQL |
| RAM footprint | Heavier (ClickHouse) | Lighter |
| Min Droplet | 2 GB ($12/mo) | 1 GB ($6/mo) |
| Dashboard polish | Very refined | Clean, simple |
| Funnels / goals | Rich (some paid-tier in cloud, all in CE) | Basic goals |
| Best for | Content sites wanting depth | Minimalists, many small sites |
Rule of thumb: choose Umami if you want the lightest possible footprint on a $6 Droplet and track a handful of sites; choose Plausible if you want richer reports and don't mind the 2 GB Droplet for ClickHouse.
The rest of this guide gives you a Docker Compose file for each — deploy whichever you picked.
3. Provision the Droplet
Create a Droplet at DigitalOcean. Get $200 in free credits for 60 days when you sign up.
| Tool | Recommended Droplet |
|---|---|
| Umami | Basic $6/mo (1 GB) |
| Plausible | Basic $12/mo (2 GB) — ClickHouse needs headroom |
Choose Ubuntu 24.04 LTS x64, add your SSH key, pick the region closest to your visitors.
4. Base Server Setup + Docker
ssh root@YOUR_SERVER_IP
# Admin user
adduser admin && usermod -aG sudo admin
cp -r /root/.ssh /home/admin/ && chown -R admin:admin /home/admin/.ssh
# Harden SSH
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh
# Firewall
ufw allow OpenSSH && ufw allow 80 && ufw allow 443 && ufw enable
Install Docker (re-login as admin first):
sudo apt update && sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker $USER && newgrp docker
5A. Deploy Umami
Create ~/umami/docker-compose.yml:
version: "3.9"
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
restart: always
ports:
- "127.0.0.1:3000:3000"
environment:
DATABASE_URL: postgresql://umami:${DB_PASS}@db:5432/umami
DATABASE_TYPE: postgresql
APP_SECRET: ${APP_SECRET}
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
restart: always
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: ${DB_PASS}
volumes:
- umami-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U umami"]
interval: 5s
timeout: 5s
retries: 10
volumes:
umami-db:
Create ~/umami/.env:
DB_PASS=change_me_long_random
APP_SECRET=change_me_64_char_random
cd ~/umami
docker compose up -d
Default login is admin / umami — change the password immediately after first login.
5B. Deploy Plausible
Plausible Community Edition ships its own compose setup. Create ~/plausible/docker-compose.yml:
version: "3.9"
services:
plausible_db:
image: postgres:16-alpine
restart: always
volumes:
- plausible-db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
plausible_events_db:
image: clickhouse/clickhouse-server:24.3-alpine
restart: always
volumes:
- plausible-events:/var/lib/clickhouse
ulimits:
nofile: { soft: 262144, hard: 262144 }
plausible:
image: ghcr.io/plausible/community-edition:v2
restart: always
command: sh -c "/entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
depends_on:
- plausible_db
- plausible_events_db
ports:
- "127.0.0.1:8000:8000"
environment:
BASE_URL: https://stats.yourdomain.com
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@plausible_db:5432/plausible_db
CLICKHOUSE_DATABASE_URL: http://plausible_events_db:8123/plausible_events_db
volumes:
plausible-db:
plausible-events:
Create ~/plausible/.env:
POSTGRES_PASSWORD=change_me_long_random
SECRET_KEY_BASE=change_me_64_char_random
Generate the secret:
openssl rand -base64 48
cd ~/plausible
docker compose up -d
docker compose logs -f plausible # watch migrations complete
6. Nginx Reverse Proxy + HTTPS
Both tools listen on 127.0.0.1 (localhost only) — Nginx handles public traffic and TLS.
sudo apt install -y nginx certbot python3-certbot-nginx
Create /etc/nginx/sites-available/analytics:
server {
listen 80;
server_name stats.yourdomain.com;
location / {
# Umami: proxy to 3000 | Plausible: proxy to 8000
proxy_pass http://127.0.0.1:3000;
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;
}
}
sudo ln -s /etc/nginx/sites-available/analytics /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d stats.yourdomain.com
Point a DNS A record for stats.yourdomain.com at your Droplet IP first.
7. Add the Tracking Snippet
Umami — Settings → Websites → Add website → copy the snippet:
<script defer src="https://stats.yourdomain.com/script.js"
data-website-id="YOUR-WEBSITE-ID"></script>
Plausible — add your site in the dashboard, then:
<script defer data-domain="yourdomain.com"
src="https://stats.yourdomain.com/js/script.js"></script>
Drop the snippet into your site's <head>. In Next.js, add it to app/layout.tsx with the next/script component:
import Script from 'next/script';
// inside <head> or the root layout body:
<Script
defer
data-domain="yourdomain.com"
src="https://stats.yourdomain.com/js/script.js"
strategy="afterInteractive"
/>
8. GDPR & Cookieless Notes
Both Plausible and Umami are cookieless and store no personal data — no persistent identifiers, no cross-site tracking, IPs are hashed/discarded. In practice this means:
- No cookie-consent banner required in most jurisdictions (always confirm with your own legal counsel for your region).
- Metrics are aggregate: page views, referrers, countries, devices — not individuals.
- Data lives on your server in your chosen region, simplifying data-residency requirements.
This is the same privacy posture ToolsHubKit takes with its local-first tools: measure what you need, retain nothing you don't.
9. Backups
Back up the Postgres volume nightly to DigitalOcean Spaces:
sudo apt install -y s3cmd
s3cmd --configure # enter Spaces keys + endpoint
~/backup-analytics.sh:
#!/bin/bash
set -e
STAMP=$(date +%Y%m%d)
# Umami (adjust container name / db as needed)
docker exec umami-db-1 pg_dump -U umami umami | gzip | \
s3cmd put - s3://your-bucket/analytics/umami-$STAMP.sql.gz
# Keep 14 days
s3cmd ls s3://your-bucket/analytics/ | awk '{print $4}' | sort | head -n -14 | xargs -r s3cmd del
chmod +x ~/backup-analytics.sh
echo "0 3 * * * admin /home/admin/backup-analytics.sh >> /var/log/analytics-backup.log 2>&1" | sudo tee /etc/cron.d/analytics-backup
10. Updates
cd ~/umami # or ~/plausible
docker compose pull
docker compose up -d
docker image prune -f
Check the project's release notes before crossing a major version — Plausible occasionally needs migration steps.
Related Guides
- Self-host your entire developer stack on one Droplet — run analytics alongside Vaultwarden, Nextcloud, and more
- GitHub Actions auto-deploy to a Droplet — automate updates to this box
- Self-host Next.js on a $6 Droplet vs Serverless — the site you'll be adding analytics to
Resources
| Resource | Link |
|---|---|
| DigitalOcean Droplets (+ $200 free credit) | Sign up here |
| Plausible Community Edition | https://github.com/plausible/community-edition |
| Umami | https://github.com/umami-software/umami |
| Umami self-hosting docs | https://umami.is/docs |
| Plausible self-hosting docs | https://plausible.io/docs/self-hosting |