Plausible Analytics Self-Hosted Installation

Plausible Analytics is a lightweight, privacy-focused web analytics platform that provides insights into website traffic without tracking users or collecting personal data. Unlike Google Analytics, Plausible respects user privacy while offering essential analytics features. This guide covers Docker Compose deployment, ClickHouse database setup, domain configuration, and tracking script implementation.

Table of Contents

Prerequisites

Ensure you have:

  • Ubuntu 20.04 LTS or later
  • Root or sudo access
  • A registered domain name
  • Minimum 2GB RAM (4GB+ recommended)
  • 20GB available disk space
  • Basic Linux administration knowledge

Update system:

sudo apt update && sudo apt upgrade -y

System Requirements

Verify system specifications:

Check OS version:

cat /etc/os-release
uname -m

Check available resources:

free -h
df -h

Docker Installation

Install Docker and Docker Compose:

sudo apt install -y docker.io docker-compose

Add user to docker group:

sudo usermod -aG docker $USER
newgrp docker

Verify installation:

docker --version
docker-compose --version

Start Docker:

sudo systemctl start docker
sudo systemctl enable docker

ClickHouse Setup

Create ClickHouse data directory:

sudo mkdir -p /var/lib/clickhouse
sudo chown -R $USER:$USER /var/lib/clickhouse

Create ClickHouse container:

docker run -d \
  --name clickhouse \
  --volume /var/lib/clickhouse:/var/lib/clickhouse \
  --publish 8123:8123 \
  --publish 9000:9000 \
  yandex/clickhouse-server:latest

Verify ClickHouse is running:

docker ps | grep clickhouse

Test ClickHouse connection:

docker exec clickhouse curl -s http://localhost:8123/

Plausible Docker Deployment

Create Plausible directory:

mkdir -p /opt/plausible
cd /opt/plausible

Generate secret key:

openssl rand -base64 64 > admin_key

Create docker-compose.yml:

nano docker-compose.yml

Add configuration:

version: '3.3'

services:
  plausible:
    image: plausible/analytics:latest
    restart: always
    ports:
      - 8000:8000
    env_file:
      - plausible-conf.env
    depends_on:
      - clickhouse
      - postgres
    networks:
      - plausible

  postgres:
    image: postgres:13-alpine
    restart: always
    volumes:
      - /var/lib/postgresql:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: SecurePassword123!
    networks:
      - plausible

  clickhouse:
    image: yandex/clickhouse-server:latest
    restart: always
    volumes:
      - /var/lib/clickhouse:/var/lib/clickhouse
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    networks:
      - plausible

networks:
  plausible:
    driver: bridge

Create plausible-conf.env:

nano plausible-conf.env

Add environment variables:

[email protected]
ADMIN_USER_NAME=admin
ADMIN_USER_PWD=SecurePassword123!
BASE_URL=https://analytics.example.com
SECRET_KEY_BASE=$(cat admin_key)
ENVIRONMENT_NAME=production
ENVIRONMENT_URL=https://analytics.example.com
LOG_LEVEL=warn
DATABASE_URL=postgres://postgres:SecurePassword123!@postgres:5432/plausible
CLICKHOUSE_DATABASE_URL=http://clickhouse:8123/plausible
CLICKHOUSE_QUERY_TIMEOUT=90

Start Plausible containers:

docker-compose up -d

Verify containers are running:

docker-compose ps
docker-compose logs -f plausible

Create tables in ClickHouse:

docker exec plausible plausible eval "Plausible.Repo.query_all(\"CREATE TABLE IF NOT EXISTS raw_event_data (domain String, timestamp UInt32, user_id String, session_id String, hostname String, pathname String, referrer String, utm_source String, utm_medium String, utm_campaign String, utm_content String, utm_term String, country_code String, subdivision1_code String, city_geoname_id UInt32, screen_size String, operating_system String, operating_system_version String, browser String, browser_version String, converted UInt32) Engine = MergeTree PARTITION BY toYYYYMM(toDateTime(timestamp)) ORDER BY (domain, timestamp);\")"

Nginx Configuration

Install Nginx:

sudo apt install -y nginx

Create Nginx configuration:

sudo nano /etc/nginx/sites-available/plausible

Add configuration:

upstream plausible {
    server localhost:8000;
}

server {
    listen 80;
    listen [::]:80;
    server_name analytics.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name analytics.example.com;

    ssl_certificate /etc/letsencrypt/live/analytics.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/analytics.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    client_max_body_size 50M;

    location / {
        proxy_pass http://plausible;
        proxy_http_version 1.1;
        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;
    }
}

Enable site:

sudo ln -s /etc/nginx/sites-available/plausible /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl start nginx
sudo systemctl enable nginx

SSL Certificate Setup

Install Certbot:

sudo apt install -y certbot python3-certbot-nginx

Obtain SSL certificate:

sudo certbot certonly --standalone -d analytics.example.com

Verify certificate:

sudo openssl x509 -in /etc/letsencrypt/live/analytics.example.com/fullchain.pem -noout -dates

Set up auto-renewal:

sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

Admin Configuration

Access Plausible dashboard:

Navigate to https://analytics.example.com

Login with admin credentials configured in environment.

Configure account settings:

  1. Settings → Account

    • Update account information
    • Change password
  2. Settings → API

    • Generate API token for programmatic access

Create website:

  1. Click "Add website"
  2. Enter domain name (example.com)
  3. Get tracking script
  4. Configure settings

Configure traffic goals:

  1. Website Settings → Goals
  2. Add goals for specific events (signups, conversions)

Tracking Script Setup

Add Plausible tracking script to your website:

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

Add to website HTML head section before closing tag.

For WordPress, add to theme header.php:

<script defer data-domain="<?php echo $_SERVER['HTTP_HOST']; ?>" src="https://analytics.example.com/js/script.js"></script>

Verify tracking is working:

  1. Add script to website
  2. Visit your website
  3. Check dashboard for pageviews
  4. May take 1-2 minutes to appear

Configure event tracking (optional):

<script>
window.plausible = window.plausible || function() {
  (window.plausible.q = window.plausible.q || []).push(arguments)
};
</script>

<button onclick="plausible('Signup')">Sign up</button>

Backup Strategy

Create backup script:

sudo nano /usr/local/bin/plausible-backup.sh

Add:

#!/bin/bash

BACKUP_DIR="/backups/plausible"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# Database backup
docker exec postgres pg_dump -U postgres plausible | gzip > "$BACKUP_DIR/plausible-db-$DATE.sql.gz"

# ClickHouse backup
docker exec clickhouse clickhouse-client --query "BACKUP DATABASE plausible TO File('/backups/plausible-ch-$DATE.tar.gz')"

# Keep only 30 days
find $BACKUP_DIR -type f -mtime +30 -delete

echo "Backup completed: $DATE"

Make executable:

sudo chmod +x /usr/local/bin/plausible-backup.sh

Schedule daily backups:

sudo crontab -e

Add:

0 2 * * * /usr/local/bin/plausible-backup.sh >> /var/log/plausible-backup.log 2>&1

Update Plausible:

cd /opt/plausible
docker-compose pull
docker-compose up -d

Conclusion

Plausible Analytics is now fully deployed as a privacy-focused web analytics platform. With ClickHouse database, PostgreSQL backend, Nginx reverse proxy, and SSL encryption, you have a complete analytics solution. Track website traffic, monitor user behavior, and measure goals without compromising user privacy. Regular backups ensure data protection and analytics continuity.