Self-Hosting

Self-Host Privacy-First Analytics (Plausible or Umami) on DigitalOcean

By ToolsHubKit EngineeringUpdated August 11, 202614 min read

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

bash
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):

bash
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:

yaml
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:

env
DB_PASS=change_me_long_random
APP_SECRET=change_me_64_char_random
bash
cd ~/umami
docker compose up -d

Default login is admin / umamichange the password immediately after first login.


5B. Deploy Plausible

Plausible Community Edition ships its own compose setup. Create ~/plausible/docker-compose.yml:

yaml
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:

env
POSTGRES_PASSWORD=change_me_long_random
SECRET_KEY_BASE=change_me_64_char_random

Generate the secret:

bash
openssl rand -base64 48
bash
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.

bash
sudo apt install -y nginx certbot python3-certbot-nginx

Create /etc/nginx/sites-available/analytics:

nginx
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;
    }
}
bash
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:

html
<script defer src="https://stats.yourdomain.com/script.js"
        data-website-id="YOUR-WEBSITE-ID"></script>

Plausible — add your site in the dashboard, then:

html
<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:

tsx
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:

bash
sudo apt install -y s3cmd
s3cmd --configure   # enter Spaces keys + endpoint

~/backup-analytics.sh:

bash
#!/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
bash
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

bash
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.



  • PII Redactor — scrub personal data from logs and exports, matching the privacy-first goal of ditching GA.
  • JSON Formatter — read and validate the JSON config and API responses from your analytics instance.

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

Frequently Asked Questions

Plausible or Umami — which should I choose?+
Pick Umami for the lightest footprint (runs on a $6 Droplet) and many small sites. Pick Plausible for richer reports and funnels, budgeting a 2 GB Droplet because it also runs ClickHouse.
Do self-hosted analytics need a cookie-consent banner?+
Plausible and Umami are cookieless and store no personal data, so in most jurisdictions no consent banner is required. Always confirm with your own legal counsel for your region.
What size Droplet do I need?+
Umami runs comfortably on a 1 GB / $6 Droplet. Plausible needs a 2 GB / $12 Droplet for ClickHouse headroom.
Is self-hosted analytics really private compared to Google Analytics?+
Yes — data lives on your server in your chosen region, with no cross-site tracking or persistent identifiers and IPs hashed or discarded. You own the data end to end.