SELF-HOST, WITHOUT THE GUESSWORK

How to Self-Host Plausible Analytics on a VPS (Production Setup)

Run Plausible Analytics on your own VPS. Privacy-friendly, lightweight analytics without monthly fees.

How to Self-Host Plausible Analytics on a VPS (Production Setup)

Plausible is a privacy-friendly alternative to Google Analytics. Lightweight script, no cookies, GDPR compliant by default.

Self-hosting Plausible means you own your analytics data and avoid monthly SaaS fees. The Community Edition is fully featured.

What you will have at the end

Step 1: Prepare the server

sudo apt update && sudo apt upgrade -y

Install Docker if needed:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker

Step 2: Clone the Community Edition repository

mkdir -p ~/apps
cd ~/apps
git clone https://github.com/plausible/community-edition.git plausible
cd plausible

Step 3: Create docker-compose.yml with Traefik

Create or modify docker-compose.yml:

services:
  traefik:
    image: traefik:v2.11
    command:
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.letsencrypt.acme.tlschallenge=true
      - [email protected]
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
    ports:
      - 80:80
      - 443:443
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt:/letsencrypt
    restart: unless-stopped

  plausible_db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: plausible
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: plausible
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U plausible"]
      interval: 10s
      timeout: 5s
      retries: 5

  plausible_events_db:
    image: clickhouse/clickhouse-server:24.3-alpine
    restart: unless-stopped
    volumes:
      - clickhouse_data:/var/lib/clickhouse
      - clickhouse_logs:/var/log/clickhouse-server
    ulimits:
      nofile:
        soft: 262144
        hard: 262144

  plausible:
    image: ghcr.io/plausible/community-edition:v2.1
    restart: unless-stopped
    depends_on:
      plausible_db:
        condition: service_healthy
      plausible_events_db:
        condition: service_started
    command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
    environment:
      - BASE_URL=https://analytics.your-domain.com
      - SECRET_KEY_BASE=${SECRET_KEY_BASE}
      - TOTP_VAULT_KEY=${TOTP_VAULT_KEY}
      - DATABASE_URL=postgres://plausible:${POSTGRES_PASSWORD}@plausible_db:5432/plausible
      - CLICKHOUSE_DATABASE_URL=http://plausible_events_db:8123/plausible_events_db
      - DISABLE_REGISTRATION=invite_only
    labels:
      - traefik.enable=true
      - traefik.http.routers.plausible.rule=Host(`analytics.your-domain.com`)
      - traefik.http.routers.plausible.entrypoints=websecure
      - traefik.http.routers.plausible.tls=true
      - traefik.http.routers.plausible.tls.certresolver=letsencrypt
      - traefik.http.services.plausible.loadbalancer.server.port=8000

volumes:
  letsencrypt:
  postgres_data:
  clickhouse_data:
  clickhouse_logs:

Step 4: Configure environment variables

Create .env file:

# Generate secrets
SECRET_KEY_BASE=$(openssl rand -base64 48 | tr -d '\n')
TOTP_VAULT_KEY=$(openssl rand -base64 32 | tr -d '\n')
POSTGRES_PASSWORD=$(openssl rand -hex 16)

cat > .env << EOF
SECRET_KEY_BASE=$SECRET_KEY_BASE
TOTP_VAULT_KEY=$TOTP_VAULT_KEY
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
EOF

Save these values. You need them for recovery.

Step 5: Deploy

docker compose up -d

First startup takes a minute as databases initialize.

Step 6: Create admin account

Visit https://analytics.your-domain.com and register your account.

If DISABLE_REGISTRATION is set to invite_only, create via console:

docker compose exec plausible /entrypoint.sh create-admin

Step 7: Add your first site

  1. Log into the dashboard
  2. Click "Add Website"
  3. Enter your domain
  4. Copy the tracking script

Step 8: Add tracking to your site

Add this script to your website's <head>:

<script defer data-domain="your-site.com" src="https://analytics.your-domain.com/js/script.js"></script>

For SPAs, use script.hash.js. For outbound link tracking, use script.outbound-links.js.

Backup strategy

Plausible needs PostgreSQL and ClickHouse backups.

#!/bin/bash
# Daily backup script
BACKUP_DIR=/backups/plausible/$(date +%Y%m%d)
mkdir -p $BACKUP_DIR

# Postgres dump (config, users, sites)
docker exec plausible-plausible_db-1 pg_dump -U plausible plausible > $BACKUP_DIR/postgres.sql

# ClickHouse backup (events data - can be large)
docker exec plausible-plausible_events_db-1 clickhouse-client --query "BACKUP DATABASE plausible_events_db TO Disk('backups', 'daily')"

# Compress
tar -czf $BACKUP_DIR.tar.gz $BACKUP_DIR

Note: ClickHouse data can be large. Consider incremental backups for high-traffic sites.

Troubleshooting

Script not tracking visits

ClickHouse fails to start

Dashboard shows no data

High disk usage from ClickHouse

Internal links

From across the StoicSoft network

Hand-curated reads on the same topic from sister sites in the StoicSoft family.