Skip to main content

Open-source alternatives guide

Self-Host Plausible: Privacy-First Analytics Setup 2026

Self-host Plausible Analytics as a Google Analytics alternative in 2026. AGPL 3.0, ~21K stars — lightweight 1KB script, GDPR-compliant, no cookies needed.

·OSSAlt Team
Share:

TL;DR

Plausible Analytics (AGPL 3.0, ~21K GitHub stars, Elixir + ClickHouse) is a lightweight, privacy-first web analytics tool. The tracking script is under 1KB (vs 45KB for Google Analytics 4), has no cookies, is GDPR-compliant without a consent banner, and collects only what you need — page views, referrers, goals, and device info. Self-hosted Plausible gives you the full product free. Plausible Cloud starts at $9/month for 10K pageviews.

Key Takeaways

  • Plausible: AGPL 3.0, ~21K stars, Elixir + ClickHouse — privacy-first, no cookies
  • 1KB script: Loads 45x faster than Google Analytics 4 (45KB)
  • GDPR without consent: No personal data stored, no cookies — no banner needed in most jurisdictions
  • ClickHouse: Time-series analytics database that scales to billions of events
  • Goals and events: Track conversions, button clicks, form submissions
  • Shared dashboards: Public or password-protected stats pages

Plausible vs Google Analytics vs Umami

FeaturePlausibleGoogle Analytics 4Umami
LicenseAGPL 3.0ProprietaryMIT
Script size~1KB~45KB~22KB
CookiesNoneYesNone
GDPR consent neededUsually noYesUsually no
Data ownershipYoursGoogleYours
RealtimeYesYesYes
Goals/EventsYesYesYes
FunnelsYesYesNo
User journeyNoYesNo
DatabaseClickHouseGoogle infraPostgreSQL
RAM (idle)~500MB~200MB

Part 1: Docker Setup

Plausible requires ClickHouse for analytics storage. The official repo provides a full Docker Compose setup:

# Download official config:
git clone https://github.com/plausible/community-edition plausible
cd plausible

The community edition includes docker-compose.yml and plausible-conf.env:

# docker-compose.yml (simplified view)
services:
  mail:
    image: bytemark/smtp:latest
    restart: always

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

  plausible:
    image: ghcr.io/plausible/community-edition:v2
    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
      - mail
    ports:
      - "8000:8000"
    env_file:
      - plausible-conf.env
# plausible-conf.env
BASE_URL=https://plausible.yourdomain.com
SECRET_KEY_BASE=<64-char-secret>   # openssl rand -base64 48
TOTP_VAULT_KEY=<32-byte-base64>    # openssl rand -base64 32
# Generate keys:
openssl rand -base64 48    # SECRET_KEY_BASE
openssl rand -base64 32    # TOTP_VAULT_KEY

docker compose up -d

Part 2: HTTPS with Caddy

plausible.yourdomain.com {
    reverse_proxy localhost:8000
}

Visit https://plausible.yourdomain.com → register your account.

Part 3: Add Your First Website

  1. + Add website in the dashboard
  2. Enter domain: yourdomain.com
  3. Get your snippet:
<script defer data-domain="yourdomain.com" src="https://plausible.yourdomain.com/js/script.js"></script>

Add to your site's <head>. That's it.

Proxy Plausible through your own domain to bypass ad blockers:

Next.js

// next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/js/script.js',
        destination: 'https://plausible.yourdomain.com/js/script.js',
      },
      {
        source: '/api/event',
        destination: 'https://plausible.yourdomain.com/api/event',
      },
    ]
  },
}
<script defer data-domain="yourdomain.com" 
  data-api="/api/event"
  src="/js/script.js">
</script>

Caddy Proxy

yourdomain.com {
    # Proxy Plausible script through your domain:
    handle /js/script.js {
        reverse_proxy plausible.yourdomain.com
    }
    handle /api/event {
        reverse_proxy plausible.yourdomain.com
    }
    # ... rest of your site
}

Update the script tag:

<script defer data-domain="yourdomain.com"
  data-api="https://yourdomain.com/api/event"
  src="https://yourdomain.com/js/script.js">
</script>

Part 5: Goals and Events

Track custom events like button clicks, signups, or form submissions:

Script variant for custom events

<script defer data-domain="yourdomain.com" 
  src="https://plausible.yourdomain.com/js/script.tagged-events.js">
</script>

Auto-tracked CSS class events

<!-- Button click automatically tracked as "Signup" goal: -->
<button class="plausible-event-name=Signup">
  Sign Up Free
</button>

<!-- With properties: -->
<button class="plausible-event-name=Purchase plausible-event-plan=pro">
  Upgrade to Pro
</button>

JavaScript API

// Track any event programmatically:
plausible('Signup', { props: { plan: 'pro', method: 'email' } })

// Track after form submit:
document.getElementById('signup-form').addEventListener('submit', function() {
  plausible('Form Submit')
})

Create Goals in Dashboard

  1. Site Settings → Goals → Add Goal
  2. Type: Pageview (e.g., /thank-you) or Custom Event (e.g., Signup)
  3. Goal appears in dashboard with conversion rate

Part 6: Funnels

Track multi-step conversion funnels:

  1. Site Settings → Funnels → Create Funnel
  2. Add steps:
    • Step 1: Pageview → /pricing
    • Step 2: Pageview → /signup
    • Step 3: Custom event → Signup
  3. See where users drop off in the funnel visualization

Part 7: Shared Dashboards

Make your stats public or share with password:

  1. Site Settings → Visibility → Make dashboard public
  2. Or: Shared links → Create link with optional password

Share URL: https://plausible.yourdomain.com/yourdomain.com

Part 8: API Access

# Get site stats:
curl "https://plausible.yourdomain.com/api/v1/stats/aggregate?site_id=yourdomain.com&period=30d&metrics=visitors,pageviews,bounce_rate" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Real-time visitors:
curl "https://plausible.yourdomain.com/api/v1/stats/realtime/visitors?site_id=yourdomain.com" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Breakdown by page:
curl "https://plausible.yourdomain.com/api/v1/stats/breakdown?site_id=yourdomain.com&period=30d&property=event:page" \
  -H "Authorization: Bearer YOUR_API_KEY"

Multi-Site Setup

One Plausible instance can host analytics for multiple sites:

  1. + Add website → enter each domain
  2. Each gets its own dashboard and tracking snippet
  3. One admin account manages all sites

Maintenance

# Update Plausible:
docker compose pull
docker compose up -d

# Backup:
# PostgreSQL (config data):
docker exec plausible_plausible_db_1 pg_dump -U postgres plausible > plausible-db-$(date +%Y%m%d).sql

# ClickHouse (events data):
tar -czf clickhouse-backup-$(date +%Y%m%d).tar.gz \
  $(docker volume inspect plausible_event-data --format '{{.Mountpoint}}')

# Logs:
docker compose logs -f plausible

Why Self-Host Plausible

Plausible Cloud pricing starts at $9/month for 10,000 monthly pageviews and jumps to $19/month for 100,000 pageviews. If you run a small blog with 50,000 monthly pageviews you're paying $228 per year — just for analytics. A SaaS startup tracking multiple properties could easily hit $49/month or more. Self-hosting Plausible gives you the full Community Edition with no pageview cap and no monthly bill. Your only ongoing cost is the VPS, typically $4–6/month on a Hetzner CX22.

Beyond cost, data ownership is the real reason most teams switch. Plausible Cloud stores your analytics data on servers in the EU, which is fine for most use cases, but some organizations — healthcare companies, law firms, government agencies — need to know exactly where data lives and who can access it. When you self-host, the answer is simple: your data is on your server and nobody else touches it. There is no vendor relationship to manage, no terms of service to review annually, and no risk of a product pivot changing your data residency situation.

Customization is another factor. The self-hosted Community Edition supports all the core Plausible features: goals, funnels, custom events, shared dashboards, and the REST API. You can embed it behind your own domain, proxy the tracking script to reduce ad-blocker interference, and integrate it with internal tooling using the API. Teams that need to embed analytics data into internal dashboards or Slack reports can do so using the API without any additional licensing cost.

One underrated advantage of self-hosting is multi-site consolidation. Plausible Cloud charges per site on some plans. Self-hosting means you can add unlimited websites to one instance — useful for agencies managing many client domains, or developers running multiple side projects.

When NOT to self-host Plausible. The ClickHouse requirement is the main hurdle. Plausible needs two databases — PostgreSQL for configuration and ClickHouse for analytics events. ClickHouse is a column-oriented analytics database that scales to billions of events, but it is not trivial to operate. At idle it consumes around 500MB of RAM, which means you need at least a 2GB VPS. If you want analytics with less operational overhead, Umami uses only PostgreSQL and runs on a $3/month instance. If you are a solo blogger with low traffic and no time to manage infrastructure, Plausible Cloud at $9/month is a fair deal.

Prerequisites

Plausible's biggest requirement is memory. ClickHouse needs about 500MB at idle and can spike to 1–2GB under query load, so plan for at least 2GB RAM total. A Hetzner CX22 (2 vCPU, 4GB RAM, 40GB SSD) at €4.50/month is the sweet spot — enough headroom for Plausible, ClickHouse, PostgreSQL, and Caddy with room to spare. If you're already running other services on the same host, bump up to a CX32 (4 vCPU, 8GB RAM) at €9.90/month. See the VPS comparison guide for a full breakdown of providers and tiers.

For Docker, you need Docker Engine 24+ and Docker Compose v2 (the docker compose command, not the older docker-compose). The Plausible Community Edition uses docker compose up -d with no extra flags. You don't need to install Elixir or ClickHouse directly — everything runs inside containers defined in the official community-edition repository.

DNS setup: create an A record pointing your analytics subdomain (e.g., plausible.yourdomain.com) to your server's IP. Caddy will automatically provision a Let's Encrypt certificate once DNS propagates, which typically takes 5–15 minutes with major registrars. Make sure port 80 and 443 are open in your firewall before starting Caddy so the ACME challenge can complete. Some providers (particularly those behind Cloudflare proxy) require you to temporarily disable the proxy during initial certificate provisioning, then re-enable it afterward.

SMTP is optional but strongly recommended. Without email configuration, you can't recover a forgotten admin password. Configure the SMTP_HOST, SMTP_PORT, and related variables in plausible-conf.env before first launch. Free SMTP services like Brevo (formerly Sendinblue) or Mailgun offer enough volume for a self-hosted analytics server.

Storage: ClickHouse stores events on disk. A busy site generating 1 million events per month will accumulate roughly 1–3GB of ClickHouse data per month. Plan your disk accordingly and consider the automated backup guide to keep ClickHouse snapshots off-server.

Production Security Hardening

Running a public-facing Plausible instance means the web UI is accessible on your domain. Without hardening, it's exposed to bots and brute-force attempts. Plausible is not a high-value target in the way a payment processor or authentication service would be, but the server it runs on is — and a compromised analytics server can be pivoted to attack other services co-hosted on the same machine.

UFW firewall. Start by blocking everything except what you need:

ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Do not expose port 8000 (Plausible app) or 19000 (ClickHouse) publicly. Caddy proxies all traffic on 443; the internal ports should stay firewalled.

Fail2ban. Protect the Plausible login endpoint from brute-force:

apt install fail2ban -y

Create /etc/fail2ban/jail.local:

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5

[sshd]
enabled = true

Restart fail2ban: systemctl restart fail2ban.

Secrets management. Never put plaintext secrets in your docker-compose.yml. Use a .env file (which is already .gitignored in the Plausible community repo) and generate secrets with openssl rand:

openssl rand -base64 48   # SECRET_KEY_BASE
openssl rand -base64 32   # TOTP_VAULT_KEY

Set file permissions so only root can read the .env:

chmod 600 plausible-conf.env

SSH hardening. Disable password authentication and use key-based SSH only:

# /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin no
systemctl restart sshd

Automatic security updates. Install unattended-upgrades so OS security patches apply automatically:

apt install unattended-upgrades -y
dpkg-reconfigure --priority=low unattended-upgrades

For a comprehensive hardening checklist covering all these steps and more, see the self-hosting security checklist.

Troubleshooting Common Issues

Plausible container exits immediately on startup. Check the logs first:

docker compose logs plausible

The most common cause is a missing or malformed SECRET_KEY_BASE. It must be at least 64 characters. Regenerate with openssl rand -base64 48 and restart.

ClickHouse fails to start with "can't open file" errors. ClickHouse needs specific XML config files mounted from the repo. Verify you cloned the full community-edition repo and that the ./clickhouse/ directory contains clickhouse-config.xml and clickhouse-user-config.xml. If either is missing, re-clone from https://github.com/plausible/community-edition.

"Connection refused" when visiting the Plausible URL. Check whether Caddy can reach port 8000:

curl http://localhost:8000

If this fails, the Plausible container may not have finished its startup sequence. The official compose file includes a sleep 10 before running migrations — on slow VPSes this may need to increase to 20–30 seconds. Edit the command: line in docker-compose.yml accordingly.

Tracking script blocked by ad blockers. The plausible.yourdomain.com/js/script.js path is in many ad-block filter lists. Use the proxy approach described in Part 4 to serve the script from your own domain — this bypasses nearly all ad blockers since your domain is not on any list.

No events appearing in the dashboard after installing the script. Verify the data-domain attribute exactly matches the domain you added in Plausible's dashboard, including whether it has www or not. Check the browser's network tab and confirm the /api/event POST is returning 202 Accepted. A 400 error usually means a domain mismatch.

ClickHouse using excessive disk space. By default ClickHouse does not automatically purge old data. You can configure a retention policy in the ClickHouse config, or run periodic ALTER TABLE ... DELETE statements via docker exec. The Plausible community docs include a data retention guide if you need to trim historical data. For most small sites, ClickHouse data grows slowly — a site with 100,000 monthly pageviews accumulates roughly 100–200MB of ClickHouse storage per month, which is very manageable. High-traffic sites (millions of events per month) should plan for data retention policies from the start.

Registration open to the public. By default, the Plausible Community Edition allows anyone who reaches the registration page to create an account. If your instance is publicly accessible, add DISABLE_REGISTRATION=true to plausible-conf.env after creating your admin account. This prevents new registrations while keeping your own account functional.

Funnels not appearing in the dashboard. Funnels are a Plausible v2 feature and require both goals to be set up before the funnel can be created. If the funnel option is greyed out or not visible, verify you're running Plausible Community Edition v2.x (the ghcr.io/plausible/community-edition:v2 image tag). Older community edition releases did not include funnels. Update via docker compose pull && docker compose up -d.

High ClickHouse memory usage at startup. ClickHouse allocates memory aggressively on startup and may use 1–2GB temporarily before settling to its normal footprint. On VPSes with exactly 2GB RAM, this can cause OOM kills during startup. The solution is to set max_memory_usage in the ClickHouse user config or upgrade to a 4GB RAM VPS. The Plausible community edition's included ClickHouse config already tunes memory settings conservatively, but very constrained hosts may still struggle.

See all open source analytics tools at OSSAlt.com/alternatives/google-analytics.

See open source alternatives to Plausible on OSSAlt.

The SaaS-to-Self-Hosted Migration Guide (Free PDF)

Step-by-step: infrastructure setup, data migration, backups, and security for 15+ common SaaS replacements. Used by 300+ developers.

Join 300+ self-hosters. Unsubscribe in one click.