Google Analytics is powerful, but it comes with baggage: privacy concerns, GDPR compliance headaches, cookie banners, and the nagging feeling that you're feeding Google even more data about your users.
Plausible Analytics is the antidote. It's lightweight (< 1KB script), privacy-focused, GDPR/CCPA/PECR compliant by design, and—best of all—you can self-host it on your own VPS for complete data ownership.
This guide walks you through setting up Plausible Analytics on a VPS from scratch, including Docker deployment, SSL certificates, PostgreSQL + ClickHouse configuration, and automated backups.
Why Self-Host Plausible?
| Feature | Google Analytics | Plausible Cloud | Plausible Self-Hosted |
|---|---|---|---|
| Monthly Cost | Free (you are the product) | $9-$99+/mo | ~$5-10/mo (VPS cost) |
| Data Ownership | Google owns it | Plausible hosts it | You own everything |
| GDPR Compliant | Requires consent | No consent needed | No consent needed |
| Cookie Banner | Required | Not needed | Not needed |
| Script Size | ~45KB | < 1KB | < 1KB |
| Unlimited Sites | Yes | Plan-dependent | Yes |
| Data Retention | 14 months default | Unlimited | Unlimited (your storage) |
Requirements
To self-host Plausible, you'll need:
- VPS with 2+ GB RAM (ClickHouse needs memory)
- 20+ GB storage (grows with traffic)
- Docker and Docker Compose
- Domain name (e.g., analytics.yourdomain.com)
- Basic Linux knowledge
Recommended VPS Specs
| Traffic Level | Monthly Pageviews | Recommended VPS | DanubeData Plan |
|---|---|---|---|
| Small | < 100K | 2 vCPU, 2GB RAM, 40GB | Starter (€4.49/mo) |
| Medium | 100K - 1M | 2 vCPU, 4GB RAM, 80GB | Standard (€8.99/mo) |
| Large | 1M - 10M | 4 vCPU, 8GB RAM, 160GB | Performance (€17.99/mo) |
| Enterprise | 10M+ | Dedicated CPU, 16GB+ RAM | Dedicated plans |
Step 1: Provision Your VPS
- Create a VPS on DanubeData
- Choose Ubuntu 24.04 LTS
- Select at least the Standard plan (4GB RAM recommended)
- Note your server IP address
Initial Server Setup
# SSH into your server
ssh root@YOUR_SERVER_IP
# Update system
apt update && apt upgrade -y
# Install essential tools
apt install -y curl wget git ufw
# Set up firewall
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
# Set hostname
hostnamectl set-hostname plausible
Step 2: Install Docker
# Install Docker
curl -fsSL https://get.docker.com | sh
# Install Docker Compose
apt install -y docker-compose-plugin
# Verify installation
docker --version
docker compose version
# Enable Docker to start on boot
systemctl enable docker
Step 3: Configure DNS
Point your domain to your VPS. Create an A record:
# DNS Configuration
Type: A
Name: analytics (or @ for root domain)
Value: YOUR_SERVER_IP
TTL: 300
Wait for DNS propagation (usually 5-15 minutes):
# Verify DNS
dig analytics.yourdomain.com +short
# Should return your server IP
Step 4: Download Plausible
# Create directory
mkdir -p /opt/plausible
cd /opt/plausible
# Download Plausible hosting files
git clone https://github.com/plausible/community-edition.git .
# Or download directly
curl -L https://github.com/plausible/community-edition/archive/refs/heads/master.tar.gz | tar xz --strip-components=1
Step 5: Configure Plausible
Generate Secret Key
# Generate a secure secret key
openssl rand -base64 48
# Save this output - you'll need it
Create Configuration File
# Create plausible-conf.env
cat > plausible-conf.env << 'EOF'
# Required: Base URL where Plausible will be accessible
BASE_URL=https://analytics.yourdomain.com
# Required: Secret key for encryption (generated above)
SECRET_KEY_BASE=YOUR_GENERATED_SECRET_KEY_HERE
# Optional: Disable registration after creating your account
DISABLE_REGISTRATION=invite_only
# Optional: Maximum login attempts before lockout
MAX_MIND_LICENSE_KEY=
# Database URLs (using Docker service names)
DATABASE_URL=postgres://postgres:postgres@plausible_db:5432/plausible_db
CLICKHOUSE_DATABASE_URL=http://plausible_events_db:8123/plausible_events_db
# SMTP Configuration (optional but recommended)
# MAILER_EMAIL=analytics@yourdomain.com
# SMTP_HOST_ADDR=smtp.yourdomain.com
# SMTP_HOST_PORT=587
# SMTP_USER_NAME=your_smtp_user
# SMTP_USER_PWD=your_smtp_password
# SMTP_HOST_SSL_ENABLED=true
# Google Search Console Integration (optional)
# GOOGLE_CLIENT_ID=
# GOOGLE_CLIENT_SECRET=
# IP Geolocation (optional - for country/city data)
# Sign up at https://www.maxmind.com/en/geolite2/signup
# MAXMIND_LICENSE_KEY=your_license_key
# MAXMIND_EDITION=GeoLite2-City
# Log level
LOG_LEVEL=warn
EOF
Important: Replace YOUR_GENERATED_SECRET_KEY_HERE with the key you generated, and update analytics.yourdomain.com with your actual domain.
Review Docker Compose Configuration
# View the default docker-compose.yml
cat docker-compose.yml
The default configuration includes:
- plausible: Main Plausible application
- plausible_db: PostgreSQL for user data
- plausible_events_db: ClickHouse for analytics data
Step 6: Set Up Reverse Proxy with Caddy
Caddy provides automatic HTTPS with Let's Encrypt:
# Create Caddy configuration
cat > Caddyfile << 'EOF'
analytics.yourdomain.com {
reverse_proxy plausible:8000
# Security headers
header {
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy strict-origin-when-cross-origin
}
# Gzip compression
encode gzip
# Logging
log {
output file /var/log/caddy/access.log
}
}
EOF
# Update docker-compose.yml to include Caddy
cat > docker-compose.yml << 'EOF'
services:
plausible_db:
image: postgres:16-alpine
restart: always
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=postgres
plausible_events_db:
image: clickhouse/clickhouse-server:24.3-alpine
restart: always
volumes:
- event-data:/var/lib/clickhouse
- event-logs:/var/log/clickhouse-server
- ./clickhouse/clickhouse-config.xml:/etc/clickhouse-server/config.d/logging.xml:ro
- ./clickhouse/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/logging.xml:ro
ulimits:
nofile:
soft: 262144
hard: 262144
plausible:
image: ghcr.io/plausible/community-edition:v2.1.4
restart: always
command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
depends_on:
- plausible_db
- plausible_events_db
env_file:
- plausible-conf.env
caddy:
image: caddy:2-alpine
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-data:/data
- caddy-config:/config
- caddy-logs:/var/log/caddy
depends_on:
- plausible
volumes:
db-data:
event-data:
event-logs:
caddy-data:
caddy-config:
caddy-logs:
EOF
Create ClickHouse Config Files
# Create ClickHouse config directory
mkdir -p clickhouse
# ClickHouse logging config
cat > clickhouse/clickhouse-config.xml << 'EOF'
warning
true
EOF
cat > clickhouse/clickhouse-user-config.xml << 'EOF'
0
0
EOF
Step 7: Launch Plausible
# Start all services
docker compose up -d
# Watch the logs
docker compose logs -f
# Wait for "Starting Plausible server..." message
# Then press Ctrl+C to exit logs
Verify Services Are Running
# Check all containers
docker compose ps
# Expected output:
# NAME STATUS
# plausible-caddy-1 Up
# plausible-plausible-1 Up
# plausible-plausible_db-1 Up
# plausible-plausible_events_db-1 Up
Step 8: Create Your Account
- Visit
https://analytics.yourdomain.com - Click "Register" to create your admin account
- Verify your email (if SMTP is configured)
- Add your first website
Disable Public Registration
After creating your account, disable registration to prevent others from signing up:
# Edit configuration
nano plausible-conf.env
# Change to:
DISABLE_REGISTRATION=true
# Restart Plausible
docker compose restart plausible
Step 9: Add Tracking Script to Your Website
After adding your site in Plausible, add this script to your website:
<!-- Plausible Analytics -->
<script defer data-domain="yourdomain.com" src="https://analytics.yourdomain.com/js/script.js"></script>
Script Variants
<!-- Track outbound links -->
<script defer data-domain="yourdomain.com" src="https://analytics.yourdomain.com/js/script.outbound-links.js"></script>
<!-- Track file downloads -->
<script defer data-domain="yourdomain.com" src="https://analytics.yourdomain.com/js/script.file-downloads.js"></script>
<!-- Track 404 pages -->
<script defer data-domain="yourdomain.com" src="https://analytics.yourdomain.com/js/script.404.js"></script>
<!-- All features combined -->
<script defer data-domain="yourdomain.com" src="https://analytics.yourdomain.com/js/script.outbound-links.file-downloads.js"></script>
Step 10: Set Up Automated Backups
Protect your analytics data with automated backups to S3:
#!/bin/bash
# /opt/plausible/backup.sh
set -e
BACKUP_DIR="/opt/plausible/backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
S3_BUCKET="your-backup-bucket"
mkdir -p $BACKUP_DIR
echo "=== Plausible Backup: $DATE ==="
# Backup PostgreSQL
echo "Backing up PostgreSQL..."
docker compose exec -T plausible_db pg_dump -U postgres plausible_db | gzip > "$BACKUP_DIR/postgres_$DATE.sql.gz"
# Backup ClickHouse
echo "Backing up ClickHouse..."
docker compose exec -T plausible_events_db clickhouse-client --query="SELECT * FROM plausible_events_db.events FORMAT Native" | gzip > "$BACKUP_DIR/clickhouse_events_$DATE.native.gz"
# Backup configuration
echo "Backing up configuration..."
cp plausible-conf.env "$BACKUP_DIR/plausible-conf_$DATE.env"
cp docker-compose.yml "$BACKUP_DIR/docker-compose_$DATE.yml"
# Create combined archive
echo "Creating archive..."
tar -czf "$BACKUP_DIR/plausible_backup_$DATE.tar.gz"
"$BACKUP_DIR/postgres_$DATE.sql.gz"
"$BACKUP_DIR/clickhouse_events_$DATE.native.gz"
"$BACKUP_DIR/plausible-conf_$DATE.env"
"$BACKUP_DIR/docker-compose_$DATE.yml"
# Upload to S3
echo "Uploading to S3..."
rclone copy "$BACKUP_DIR/plausible_backup_$DATE.tar.gz" "danubedata:$S3_BUCKET/plausible/"
# Cleanup old local backups (keep last 7 days)
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
find $BACKUP_DIR -name "*.sql.gz" -mtime +1 -delete
find $BACKUP_DIR -name "*.native.gz" -mtime +1 -delete
find $BACKUP_DIR -name "*.env" -mtime +1 -delete
find $BACKUP_DIR -name "*.yml" -mtime +1 -delete
echo "=== Backup complete! ==="
# Make executable
chmod +x /opt/plausible/backup.sh
# Test backup
/opt/plausible/backup.sh
# Add to cron (daily at 3 AM)
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/plausible/backup.sh >> /var/log/plausible-backup.log 2>&1") | crontab -
Step 11: Enable GeoIP (Optional)
To see country/city data for visitors:
- Sign up for a free MaxMind account at maxmind.com
- Generate a license key
- Add to your configuration:
# Edit plausible-conf.env
MAXMIND_LICENSE_KEY=your_license_key
MAXMIND_EDITION=GeoLite2-City
# Restart
docker compose restart plausible
Step 12: Monitoring and Maintenance
Check Disk Usage
# Check Docker volumes
docker system df -v
# Check ClickHouse data size
docker compose exec plausible_events_db du -sh /var/lib/clickhouse
View Logs
# All logs
docker compose logs -f
# Specific service
docker compose logs -f plausible
docker compose logs -f plausible_events_db
Update Plausible
# Pull latest image
docker compose pull
# Restart with new version
docker compose up -d
# Check version
docker compose logs plausible | grep "Running Plausible"
Advanced Configuration
Custom Goals and Events
Track custom events in your application:
// JavaScript
plausible('Signup', {props: {plan: 'Premium'}});
plausible('Download', {props: {file: 'whitepaper.pdf'}});
plausible('Purchase', {props: {product: 'Pro Plan', value: '99'}});
API Access
Plausible provides an API for programmatic access:
# Get stats via API
curl "https://analytics.yourdomain.com/api/v1/stats/aggregate"
-H "Authorization: Bearer YOUR_API_KEY"
-d "site_id=yourdomain.com"
-d "period=30d"
-d "metrics=visitors,pageviews,bounce_rate"
Shared Links
Create public dashboard links for clients or stakeholders:
- Go to Site Settings → Visibility
- Enable "Public Dashboard" or create a "Shared Link"
- Optionally add password protection
Troubleshooting
Common Issues
# Container won't start
docker compose logs plausible
# Look for database connection errors
# SSL certificate issues
docker compose logs caddy
# Check domain DNS resolution
# High memory usage
# ClickHouse can be memory-hungry
# Consider upgrading VPS or tuning ClickHouse settings
# No data showing
# 1. Check script is loading (browser dev tools)
# 2. Check domain matches exactly
# 3. Check for ad blockers
# 4. Verify Plausible container is healthy
Reset Admin Password
# Access Plausible console
docker compose exec plausible /app/bin/plausible remote
# Reset password
Plausible.Auth.find_user_by(email: "your@email.com") |> Plausible.Auth.User.set_password("new_password") |> Plausible.Repo.update()
Cost Comparison
Let's compare the real costs:
| Pageviews/Month | Plausible Cloud | Self-Hosted (DanubeData) | Annual Savings |
|---|---|---|---|
| 10K | $9/mo ($108/yr) | €4.49/mo (~€54/yr) | ~$54/yr |
| 100K | $19/mo ($228/yr) | €4.49/mo (~€54/yr) | ~$174/yr |
| 1M | $69/mo ($828/yr) | €8.99/mo (~€108/yr) | ~$720/yr |
| 10M | $189/mo ($2,268/yr) | €17.99/mo (~€216/yr) | ~$2,052/yr |
Bottom line: Self-hosting Plausible saves $174-$2,000+/year depending on traffic, plus you get unlimited sites, unlimited data retention, and complete data ownership.
Get Started Today
Ready to take control of your analytics?
- Create a VPS on DanubeData (€4.49/mo for small sites)
- Follow this guide to deploy Plausible
- Add the tracking script to your sites
- Enjoy privacy-friendly, GDPR-compliant analytics
DanubeData VPS for Plausible:
- €4.49/mo Starter plan handles most small-medium sites
- €8.99/mo Standard plan for higher traffic
- NVMe storage for fast ClickHouse queries
- German data center (GDPR-friendly)
- 20TB included traffic
Need help setting up Plausible? Contact our team—we're happy to help.