Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Plausible Ubuntu
GUIDEInstall Guides

How to Install Plausible Analytics on Ubuntu 24.04

26 min read

How to Install Plausible Analytics on Ubuntu 24.04 — A Privacy-First Google Analytics Alternative

Self-hosting your own analytics stack gives you complete ownership of visitor data, eliminates the monthly SaaS fee, and keeps you on the right side of privacy regulations without the cookie-banner circus. This guide walks you through installing Plausible Community Edition on an Ubuntu 24.04 VPS — from Docker setup to a TLS-terminated, production-hardened deployment serving a lightweight sub-1 KB tracking script.

Skip the setup? Deploy Plausible in one click with our pre-configured Analytics image. Launch an analytics-ready VPS and start collecting page views in under 60 seconds.

Table of Contents

  • What is Plausible Analytics?
  • Why Self-Host Plausible?
  • Licensing: Plausible Community Edition (AGPL)
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install Docker and Docker Compose
  • Step 3: Clone the Community Edition Repo
  • Step 4: Generate Secrets and Edit the .env File
  • Step 5: Review the docker-compose.yml
  • Step 6: Launch the Stack
  • Step 7: First-Run Registration and Site Setup
  • Step 8: Install the Tracking Snippet and Events
  • Step 9: Nginx Reverse Proxy with TLS
  • Step 10: Backups
  • Step 11: Updating Plausible
  • Step 12: Custom Domain for the Tracking Script
  • Step 13: Import Historical Data from GA4
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Plausible Analytics?

    Plausible is an open-source, lightweight web analytics platform built in Elixir (Phoenix) on top of PostgreSQL and ClickHouse. It was created as a direct alternative to Google Analytics for people who want useful visitor metrics without the baggage: no cookies, no cross-site tracking, no data sold to advertisers, and no bloated 45 KB script slowing every page.

    The tracking script weighs in at under 1 KB (minified and gzipped). Once embedded, Plausible records page views, referrers, device/browser/OS breakdowns, country/region, entry and exit pages, session duration, and bounce rate — all the numbers most teams actually look at. It does this without storing any personal data, which means no cookie consent banner is legally required in the EU, UK, or California.

    Plausible is GDPR, CCPA, and PECR compliant by design. Visitors are counted using a daily-rotating hash of IP address + user agent + a site-specific salt, which is discarded at midnight UTC. There is no persistent identifier, no device fingerprinting, and no cross-site graph. The data that does get recorded is aggregated at query time in ClickHouse, so individual visitor logs do not exist.

    Beyond page views, Plausible supports custom events, conversion goals, funnels (a Community Edition feature since v2.0), outbound link clicks, file download tracking, 404 tracking, campaign UTM attribution, and shareable public dashboards. All of this from a single container plus two databases.

    Typical users include indie hackers, SaaS companies, privacy-focused publishers, agencies managing client sites, and EU-based businesses that want to avoid the legal grey zone around Google Analytics under the Schrems II ruling.

    Why Self-Host Plausible?

    Plausible sells a hosted version at plausible.io starting at $9/month for 10,000 page views. It is an excellent product and if you value zero maintenance, it is worth the fee. But running your own instance on a VPS offers several concrete advantages:

    • Flat-rate cost at any traffic volume — A VPS costs the same whether you record 10,000 or 10 million page views per month. Plausible Cloud's pricing scales with traffic; at 1M page views you would pay $69/month, at 10M you pay $269/month. A €7.99/month VPS handles millions of monthly page views easily.
    • Complete data ownership — The event data lives in your own ClickHouse database on your own server. You can query it directly with SQL, export it to a warehouse, pipe it into a BI tool, or feed it into your own dashboards. Nothing leaves your infrastructure.
    • Unlimited sites and team members — The hosted plans limit both. Community Edition has no caps — add a thousand sites and a hundred users on the same instance if you need to.
    • Data sovereignty for EU compliance — If you are in the EU and worried about Schrems II and US CLOUD Act exposure, hosting the instance yourself on an EU-based VPS puts you on firm legal ground. You choose the jurisdiction.
    • Customization and modding — Because it is AGPL source-available, you can modify the dashboard, add custom reports, integrate with your own auth provider, or build plugins. The hosted version does not let you do this.
    • Compared to GA4 — Google Analytics 4 is free, but the trade-off is sending every visitor through Google's advertising graph, maintaining a cookie consent banner, navigating a UI that has been widely criticized for being unusable, and accepting that data retention defaults to 2 months. Plausible gives you a dashboard that a non-analyst can read in 30 seconds, indefinite data retention, and no consent banner required.

    Cost Comparison: Self-Hosted vs. Plausible Cloud vs. GA4

    ScenarioPlausible CloudGoogle Analytics 4Self-Hosted Plausible (VPS)
    Monthly cost (100K views)$19/moFree€7.99/mo
    Monthly cost (1M views)$69/moFree€7.99/mo
    Monthly cost (10M views)$269/moFree€7.99/mo
    Cookie banner required?NoYesNo
    Data retentionUnlimited2-14 monthsUnlimited (your disk)
    Data ownershipShared with PlausibleGoogle100% yours
    SQL access to raw dataNoBigQuery export (paid)Yes (direct ClickHouse)
    Custom domain trackerPaid add-onNoYes (free)
    FunnelsBusiness planYes (complex)Yes (included)
    For anyone running more than one or two sites, or pushing over about 100K monthly page views, the self-hosted VPS approach starts saving money from month one.

    Licensing: Plausible Community Edition (AGPL)

    A quick note before you install. Plausible Community Edition (the code at github.com/plausible/community-edition) is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). This is important because AGPL extends copyleft to network use: if you modify Plausible and expose it over a network (for example, you tweak the dashboard and let customers log in), you must make your modified source code available to those users.

    For most self-hosting scenarios — internal company use, personal projects, analytics for your own sites — you will not modify the code and the AGPL imposes no practical burden. You just run the official Docker images as-is. If you plan to fork Plausible, rebrand it, and sell access to third parties, read the AGPL carefully or contact Plausible's team about a commercial license.

    Community Edition includes the full feature set needed for a production analytics deployment: goals, funnels, custom events, team management, shared dashboards, stats API, and GA4 imports.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to your server
    • A domain name (such as analytics.yourdomain.com) with an A record pointing to the VPS public IP
    • At least 2 vCPU and 4 GB of RAM — ClickHouse is the memory-hungry component
    • At least 40 GB of disk space — most of which will be consumed by ClickHouse as event data accumulates
    • Ports 80 and 443 open for TLS certificate issuance and dashboard access
    Recommended Plan: CloudCore Starter
    >
    For a comfortable Plausible deployment that can handle millions of monthly page views across multiple sites, we recommend the CloudCore Starter plan:
    >
    - 4 vCPU cores
    - 6 GB RAM
    - 100 GB NVMe SSD
    - Unmetered bandwidth
    - €7.99/month
    >
    This gives ClickHouse enough RAM headroom for efficient aggregations and 100 GB of SSD covers years of event retention for a typical site portfolio.

    Connect to your server via SSH to get started:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Start by refreshing the package index and applying any pending security updates. This ensures a clean base before adding the Docker repository.

    bash
    sudo apt update && sudo apt upgrade -y

    Expected output (abbreviated):

    text
    Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
    Hit:2 http://archive.ubuntu.com/ubuntu noble-updates InRelease
    Reading package lists... Done
    Building dependency tree... Done
    Calculating upgrade... Done
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    If your kernel was updated, reboot before continuing:

    bash
    sudo reboot

    Then reconnect via SSH.

    Step 2: Install Docker and Docker Compose

    Plausible Community Edition runs as a Docker Compose stack. Install Docker Engine and the Compose v2 plugin from Docker's official APT repository.

    Install prerequisites and add Docker's GPG key:

    bash
    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
    sudo chmod a+r /etc/apt/keyrings/docker.gpg

    Add the Docker repository:

    bash
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
      https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

    Install Docker Engine and the Compose plugin:

    bash
    sudo apt update
    sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    Verify the install:

    bash
    docker --version
    docker compose version

    Expected output:

    text
    Docker version 27.3.1, build ce12230
    Docker Compose version v2.29.7

    Add your user to the docker group so you do not have to prefix every command with sudo (log out and back in for the change to take effect):

    bash
    sudo usermod -aG docker $USER

    For a deeper dive into Docker itself, see our Docker install guide.

    Step 3: Clone the Community Edition Repo

    Plausible publishes the recommended deployment scaffolding — a docker-compose.yml, a .env.example, and a reverse-proxy/ folder — in its Community Edition repository.

    bash
    sudo mkdir -p /opt/plausible
    sudo chown $USER:$USER /opt/plausible
    cd /opt/plausible
    git clone https://github.com/plausible/community-edition.git .

    Expected output:

    text
    Cloning into '.'...
    remote: Enumerating objects: 412, done.
    remote: Counting objects: 100% (412/412), done.
    Receiving objects: 100% (412/412), 128.45 KiB | 2.30 MiB/s, done.

    Check out the latest stable release tag (avoid main in production):

    bash
    git fetch --tags
    git checkout v2.1.5  # or whatever the current stable tag is — check the releases page

    The repository layout you will work with:

    text
    /opt/plausible/
    ├── compose.yml           # the Docker Compose definition
    ├── .env.example          # template for environment variables
    ├── reverse-proxy/        # optional Caddy-based reverse proxy configs
    └── README.md

    Step 4: Generate Secrets and Edit the .env File

    Plausible requires two cryptographically strong random values in the environment: a SECRET_KEY_BASE used by Phoenix for session signing, and a TOTP_VAULT_KEY used to encrypt TOTP secrets for two-factor authentication.

    Generate both with OpenSSL:

    bash
    openssl rand -base64 48

    Example output (yours will be different — that is the point):

    text
    f8s9Q2vN5mK3pR7xL4jH6bZ1cW8yD0tE5aG9iU2oP4qS7rX3zV6nM

    Run the command twice — once for each secret. Keep them somewhere safe (a password manager); losing SECRET_KEY_BASE will invalidate every logged-in session, and losing TOTP_VAULT_KEY will break 2FA for every user.

    Now create the .env file:

    bash
    cp .env.example .env
    nano .env

    At minimum, set the following values:

    ini
    # The canonical public URL where Plausible will be served
    BASE_URL=https://analytics.yourdomain.com

    Phoenix session signing key (48 bytes, base64)

    SECRET_KEY_BASE=f8s9Q2vN5mK3pR7xL4jH6bZ1cW8yD0tE5aG9iU2oP4qS7rX3zV6nM

    TOTP encryption key (48 bytes, base64) — DIFFERENT value from SECRET_KEY_BASE

    TOTP_VAULT_KEY=m2H7kP9wR3qT6uY1iO5aS8dF4gJ0lZ6vX2cN9bV3nM5xQ7zK1pL

    Database connections — the defaults point to the compose services

    DATABASE_URL=postgres://postgres:postgres@plausible_db:5432/plausible_db CLICKHOUSE_DATABASE_URL=http://plausible_events_db:8123/plausible_events_db

    Disable public registration once your admin account is created

    DISABLE_REGISTRATION=invite_only

    SMTP configuration (required for invite emails, password resets, weekly reports)

    [email protected] SMTP_HOST_ADDR=smtp.yourprovider.com SMTP_HOST_PORT=587 [email protected] SMTP_USER_PWD=your-smtp-password SMTP_HOST_SSL_ENABLED=true

    Key variables explained:

    • BASE_URL — Must match the public URL exactly, including the scheme (https://). This is used for generating email links, the tracking script source, and OAuth callbacks. Change it later and every embedded tracking snippet breaks.
    • SECRET_KEY_BASE — Phoenix session and CSRF token signing key. Must be at least 64 characters when base64-encoded.
    • TOTP_VAULT_KEY — Encrypts 2FA secrets at rest in Postgres. Must be different from SECRET_KEY_BASE.
    • DATABASE_URL — Connection string for the metadata Postgres (users, sites, configuration). The compose file creates this service as plausible_db.
    • CLICKHOUSE_DATABASE_URL — Connection string for the events ClickHouse (every page view and custom event). The compose file creates this as plausible_events_db.
    • DISABLE_REGISTRATION — Set to invite_only after your first user is created to prevent random people from signing up on your public instance.
    • MAILER_ / SMTP_ — Without SMTP, you cannot invite team members, reset passwords, or send weekly report emails. Use a transactional provider like Postmark, SendGrid, Amazon SES, or your own Mailcow.
    Save the file (Ctrl+O, Enter, Ctrl+X).

    Step 5: Review the docker-compose.yml

    Open the compose file to understand what is about to run:

    bash
    cat compose.yml

    The three services that matter:

    yaml
    services:
      plausible:
        image: ghcr.io/plausible/community-edition:v2.1.5
        restart: always
        depends_on:
          - plausible_db
          - plausible_events_db
        ports:
          - 127.0.0.1:8000:8000
        env_file:
          - .env

    plausible_db: image: postgres:16-alpine restart: always volumes: - db-data:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: postgres POSTGRES_USER: postgres POSTGRES_DB: plausible_db

    plausible_events_db: image: clickhouse/clickhouse-server:24.3.3.102-alpine restart: always volumes: - event-data:/var/lib/clickhouse - ./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

    Three things to notice:

  • ports: - 127.0.0.1:8000:8000 — The Plausible container is bound to localhost only. External traffic must come through an Nginx (or Caddy) reverse proxy that terminates TLS. Never expose port 8000 directly to the internet — it is HTTP only and has no rate limiting on the event endpoint.
  • Two separate databases — Postgres 16 holds account/site metadata; ClickHouse holds the event firehose. They are tuned for very different workloads (transactional vs. columnar aggregation) and swapping them is not supported.
  • Volumes — db-data and event-data are named Docker volumes. Your entire analytics history lives in event-data. Back it up.
  • Step 6: Launch the Stack

    Start everything in detached mode:

    bash
    docker compose up -d

    Expected output:

    text
    [+] Running 4/4
     ✔ Network plausible_default           Created
     ✔ Container plausible-plausible_db-1          Started
     ✔ Container plausible-plausible_events_db-1   Started
     ✔ Container plausible-plausible-1             Started

    First-time startup runs database migrations for both Postgres and ClickHouse, which typically takes 20-40 seconds. Follow the logs:

    bash
    docker compose logs -f plausible

    Wait for the line:

    text
    [info] Running PlausibleWeb.Endpoint with cowboy 2.10.0 at :::8000 (http)
    [info] Access PlausibleWeb.Endpoint at http://localhost:8000

    Press Ctrl+C to stop following logs. Verify the HTTP endpoint responds locally:

    bash
    curl -I http://127.0.0.1:8000

    Expected output:

    text
    HTTP/1.1 302 Found
    location: /login
    ...

    The redirect to /login confirms Plausible is up.

    Step 7: First-Run Registration and Site Setup

    Before exposing Plausible to the public internet, you could register locally via SSH tunnel, but it is simpler to do Step 9 (Nginx + TLS) first and register through the proper HTTPS URL. Come back to this step once https://analytics.yourdomain.com resolves.

    Once TLS is live, open https://analytics.yourdomain.com/register in your browser. You will see the account creation form:

    • Enter your name, email, and a strong password
    • Click Create my account
    • The first user registered on a fresh install becomes the instance owner with full admin rights
    After logging in, you will be prompted to add your first site:

  • Click Add a website
  • Enter the domain (without https:// or www., e.g. yourdomain.com)
  • Select the time zone for reporting
  • Click Add snippet
  • Plausible presents the tracking snippet, which you copy into the <head> of your site (see Step 8).

    Important: After your admin account is created, edit .env and set DISABLE_REGISTRATION=invite_only, then restart the container:

    bash
    docker compose restart plausible

    This prevents strangers who find your analytics URL from creating accounts. You can still invite teammates from Settings > Team.

    Step 8: Install the Tracking Snippet and Events

    The default tracking snippet looks like this:

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

    Paste it inside the <head> of every page you want tracked. For WordPress, use a plugin like Plausible for WordPress; for Next.js use the <Script> component; for plain HTML, just drop it in the template.

    Variant Scripts for Extra Features

    Plausible ships several script variants, selected by the filename:

    • script.js — basic page views only (smallest, fastest)
    • script.hash.js — page views for single-page apps using # routing
    • script.outbound-links.js — automatically tracks outbound link clicks
    • script.file-downloads.js — tracks clicks on links to .pdf, .zip, .dmg, etc.
    • script.tagged-events.js — enables manual custom events via data- attributes
    • script.exclusions.js — allows excluding specific URLs from tracking
    • script.compat.js — Internet Explorer / older browser fallback
    Stack them with a plus, e.g. script.outbound-links.file-downloads.tagged-events.js.

    Custom Events

    For tagged events (button clicks, form submissions), add class="plausible-event-name=Signup" to the element, or call the JavaScript API directly:

    html
    <button onclick="plausible('Signup', {props: {plan: 'starter'}})">
      Sign up
    </button>

    Goals and Funnels

    In the Plausible dashboard, go to Settings > Goals. Add a goal:

    • Page view goal — triggers when a specific URL is visited (e.g. /thank-you)
    • Custom event goal — triggers when a named event fires (e.g. Signup)
    • File download / outbound link — auto-populated if you use the variant script
    Goals become rows in your dashboard showing conversion count and rate.

    To build a funnel (Community Edition v2.0+), go to Settings > Funnels and chain 2-5 goals in sequence. Plausible shows drop-off between each step, which is useful for signup flows, checkout flows, and content consumption paths.

    Sharing Dashboards

    Public link sharing is useful for client reports and open dashboards. From any site's dashboard, click Share in the top right. You can:

    • Generate a public link (optionally password-protected)
    • Restrict by time range
    • Embed in an iframe
    Multiple team members can access internal dashboards via Settings > Team > Invite member with roles viewer, editor, or admin.

    Step 9: Nginx Reverse Proxy with TLS

    Plausible listens only on 127.0.0.1:8000, so you need a public-facing reverse proxy. Nginx with Certbot is the most common choice.

    Install Nginx and Certbot:

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

    Create the site configuration:

    bash
    sudo tee /etc/nginx/sites-available/plausible > /dev/null <<'EOF'
    

    Rate limit zone for the event endpoint — prevents spam from single IPs

    limit_req_zone $binary_remote_addr zone=plausible_events:10m rate=10r/s;

    server { listen 80; server_name analytics.yourdomain.com; return 301 https://$host$request_uri; }

    server { listen 443 ssl http2; server_name analytics.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/analytics.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/analytics.yourdomain.com/privkey.pem;

    # Security headers add_header X-Content-Type-Options nosniff; add_header X-Frame-Options SAMEORIGIN; add_header Referrer-Policy strict-origin-when-cross-origin;

    client_max_body_size 2m;

    # Rate-limit the event ingestion endpoint location = /api/event { limit_req zone=plausible_events burst=20 nodelay; proxy_pass http://127.0.0.1:8000; 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; }

    # Aggressive caching for the tracking script location ~ ^/js/.*\.js$ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_cache_valid 200 1h; add_header Cache-Control "public, max-age=3600"; }

    location / { proxy_pass http://127.0.0.1:8000; 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; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 60s; } } EOF

    Enable the site and issue a certificate:

    bash
    sudo ln -s /etc/nginx/sites-available/plausible /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo certbot --nginx -d analytics.yourdomain.com
    sudo systemctl reload nginx

    Certbot sets up automatic renewal via a systemd timer. Verify:

    bash
    sudo systemctl list-timers | grep certbot

    The rate limit on /api/event (10 req/sec per IP with a burst of 20) protects you from a single client firing fake events in a loop. Legitimate real-user traffic never hits this ceiling.

    For more Nginx tuning, see our Nginx configuration guide.

    Step 10: Backups

    Losing the ClickHouse volume means losing every page view you ever recorded. Back it up.

    Postgres Backup (Metadata)

    Users, sites, goals, funnels, and settings all live in Postgres. Small, but critical.

    bash
    docker compose exec -T plausible_db pg_dump -U postgres plausible_db | \
      gzip > /opt/plausible/backups/postgres-$(date +%F).sql.gz

    ClickHouse Backup (Events)

    ClickHouse supports native BACKUP TO Disk() statements. First, configure a backup disk in the ClickHouse user config (one-time setup inside the container), or use the simpler clickhouse-client approach for smaller deployments:

    bash
    mkdir -p /opt/plausible/backups
    docker compose exec -T plausible_events_db clickhouse-client \
      --query "BACKUP DATABASE plausible_events_db TO File('/var/lib/clickhouse/backup/$(date +%F)/')"
    docker compose cp plausible_events_db:/var/lib/clickhouse/backup \
      /opt/plausible/backups/clickhouse

    Automating with Cron

    Add to /etc/cron.daily/plausible-backup:

    bash
    #!/bin/bash
    cd /opt/plausible
    BDIR=/opt/plausible/backups
    mkdir -p "$BDIR"
    docker compose exec -T plausible_db pg_dump -U postgres plausible_db | gzip > "$BDIR/pg-$(date +%F).sql.gz"
    docker compose exec -T plausible_events_db clickhouse-client \
      --query "BACKUP DATABASE plausible_events_db TO File('/var/lib/clickhouse/backup/$(date +%F)/')"
    

    Prune backups older than 30 days

    find "$BDIR" -type f -mtime +30 -delete

    Make executable:

    bash
    sudo chmod +x /etc/cron.daily/plausible-backup

    Ship the /opt/plausible/backups directory off-server with rclone, restic, or borg for true disaster recovery.

    Step 11: Updating Plausible

    New Community Edition releases ship roughly every month. To update:

    bash
    cd /opt/plausible
    git fetch --tags
    git checkout v2.2.0  # or whichever is current
    docker compose pull
    docker compose up -d

    Migrations run automatically when the plausible container starts. Check the logs:

    bash
    docker compose logs -f plausible

    Look for [info] Running migrations... followed by the normal startup banner.

    Before major version upgrades (e.g., v2 -> v3): read the release notes at github.com/plausible/community-edition/releases, take a fresh backup, and test on a staging instance if you host customer-facing analytics.

    Step 12: Custom Domain for the Tracking Script

    Popular ad blockers (uBlock Origin, Brave Shields, AdGuard) maintain filter lists that block requests to known analytics domains — including plausible.io. Even if you self-host, if you serve the script from analytics.yourdomain.com long enough to show up on a list, it can get blocked.

    The workaround: proxy the tracking script through your main website's domain. Visitors loading yourdomain.com/js/stats.js are not fetching from an analytics host — they are fetching from the same origin as the page itself, which no filter list blocks by default.

    Proxy Configuration on the Main Site's Nginx

    On the webserver that hosts yourdomain.com, add these two location blocks:

    nginx
    # Serve Plausible's tracking script from our own origin
    location = /js/stats.js {
        proxy_pass https://analytics.yourdomain.com/js/script.outbound-links.js;
        proxy_set_header Host analytics.yourdomain.com;
        proxy_ssl_server_name on;
        proxy_cache_valid 200 6h;
        add_header Cache-Control "public, max-age=21600";
    }

    Forward events to the Plausible ingestion endpoint

    location = /api/event { proxy_pass https://analytics.yourdomain.com/api/event; proxy_set_header Host analytics.yourdomain.com; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_ssl_server_name on; }

    Update your tracking snippet to point to the local paths:

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

    Visitors now see only same-origin requests; the analytics hostname never appears in their network tab. This typically recovers 5-15% of measured visitors, depending on your audience's ad-blocker usage.

    Step 13: Import Historical Data from GA4

    Migrating off Google Analytics? Plausible has a built-in importer.

  • In the Plausible dashboard, go to Settings > Imports & Exports
  • Click Import from Google Analytics
  • Authenticate with your Google account
  • Select the GA4 property and date range
  • Click Confirm import
  • The import runs in the background. For busy sites with years of data, it can take anywhere from a few minutes to several hours.

    If OAuth is restricted in your environment, Plausible also accepts CSV uploads from GA4's standard reports (Reports > Acquisition > Traffic acquisition, exported as CSV). Upload the CSV via the same dialog and Plausible will backfill visitor, session, and source data into ClickHouse.

    Imported data is marked with an imported_ prefix in queries, so it is visually distinguishable in the dashboard but still aggregated into the same totals.

    Troubleshooting

    ProblemCauseSolution
    502 Bad Gateway from NginxPlausible container not running or bound to wrong portdocker compose ps; verify plausible shows Up. Check logs: docker compose logs plausible. Confirm port binding: ss -tlnp \</td><td>grep 8000.
    Events not recorded in the dashboardTracking snippet data-domain mismatch, or script blockedOpen browser DevTools > Network, reload the page, look for /api/event POST. If blocked, check ad-blocker. Ensure data-domain matches exactly what you typed when adding the site in Plausible.
    Blocked by Brave Shields / uBlock OriginVisitor browser blocks analytics.yourdomain.comFollow Step 12 to proxy the script through your main domain.
    ClickHouse disk fills upEvent retention is unlimited by defaultOld data is compressed aggressively in ClickHouse, but if your disk fills, either resize the volume or run a DELETE query with a date cutoff, or enable TTL: ALTER TABLE events_v2 MODIFY TTL timestamp + INTERVAL 3 YEAR.
    SECRET_KEY_BASE must be at least 64 bytes on startupSecret too short or not base64Regenerate with openssl rand -base64 48 and paste the entire output into .env.
    Can't register — registration is disabledFirst-run gate or DISABLE_REGISTRATION activeOn fresh install, set DISABLE_REGISTRATION=false, restart, register, then set back to invite_only.
    IPv6 connectivity issuesDocker bridge not bridging IPv6 traffic correctlyAdd "ipv6": true, "fixed-cidr-v6": "fd00::/80" to /etc/docker/daemon.json and restart Docker. Or bind Nginx to both IPv4 and IPv6 explicitly with listen [::]:443 ssl http2;.
    Dashboard loads but charts are empty for a new sitePage views take up to 30 seconds to propagate through the ingestion pipeline on a fresh installReload the page a few times, wait 30-60 seconds. If still empty after 5 minutes, check docker compose logs plausible_events_db for ClickHouse errors.
    Could not connect to SMTP on inviteSMTP credentials wrong or port blockedTest from the container: docker compose exec plausible /bin/sh -c "nc -zv $SMTP_HOST_ADDR $SMTP_HOST_PORT". Many VPS providers block outbound port 25 — use 587 with STARTTLS or 465 with implicit TLS.

    Viewing Logs

    Real-time application logs:

    bash
    docker compose logs -f plausible

    All services:

    bash
    docker compose logs -f

    Last 100 lines of ClickHouse (useful when events are not appearing):

    bash
    docker compose logs --tail=100 plausible_events_db

    FAQ

    How does Plausible compare to Umami?

    Both are open-source, privacy-first, cookieless analytics tools, and they cover 90% of the same feature territory. Umami is built in Next.js/TypeScript on Postgres (or MySQL/TimescaleDB), which makes it lighter to run — one database, one container, about 400 MB of RAM. It is a good fit for small sites and for teams that prefer a Node.js stack. Plausible uses Elixir + ClickHouse, which is heavier in idle resources but significantly faster at querying large event volumes; funnels, GA4 imports, and detailed campaign attribution are more polished. If you are tracking a handful of sites and want the simplest possible deploy, Umami. If you run many sites, need funnels, or plan to grow past 1M monthly page views, Plausible. See our Umami install guide for the alternative.

    How does Plausible compare to Fathom?

    Fathom is a commercial hosted competitor with a similar minimalist philosophy and similar pricing to Plausible Cloud. It is closed-source and cannot be self-hosted. Feature-for-feature the two are close, but Plausible's Community Edition gives you the self-hosting option, which Fathom does not.

    Does Plausible hurt my site's SEO?

    The opposite, actually. The tracking script is under 1 KB, loads asynchronously with defer, and makes no cookie or localStorage writes. Google Analytics 4's gtag.js weighs in around 45 KB and adds measurable render-blocking to Core Web Vitals. If you are chasing Lighthouse scores or PageSpeed Insights, switching from GA4 to Plausible typically improves LCP (Largest Contentful Paint) by 50-150 ms and reduces total JavaScript payload. Plausible also does not send data to third-party domains by default, which keeps the request graph cleaner.

    Do I really not need a cookie consent banner?

    For the default Plausible configuration, no — because the tool sets no cookies and stores no personal data. The daily-rotating anonymous hash used to count unique visitors is not personal data under GDPR's definition, and has been validated by European data protection authorities (notably France's CNIL and the Dutch DPA). This is the single biggest operational win over GA4. One caveat: if you enable custom events with PII in the props (e.g., passing an email address as a property), that becomes personal data and consent rules apply. Stick to anonymous event properties.

    Is there a limit on the number of funnels?

    Plausible Cloud's Business plan includes funnels with no per-account cap. Community Edition has no limits at all — you can create as many funnels, goals, and custom events as you want. The only real constraint is ClickHouse memory when running complex funnel queries over years of data on large sites; 4 GB of RAM handles this comfortably up to a few million monthly events.

    Can I host analytics for multiple tenants / customers on one instance?

    Yes. Create a site per tenant, invite the tenant's user as a viewer or editor on only their site, and they will see only their own data. Community Edition has no seat or site limit, so one VPS can serve an agency's entire client roster. For fully isolated multi-tenancy (separate databases per customer), you would need to run multiple Plausible instances — one per tenant — which is straightforward with Docker Compose but obviously costs more RAM.

    Does Plausible support Single Sign-On (SSO)?

    Community Edition supports email/password and TOTP 2FA. SAML/OIDC SSO is only available in the hosted Plausible Cloud Enterprise plan. If you need SSO on a self-hosted instance, you can put Plausible behind an identity-aware reverse proxy like oauth2-proxy or Authelia, which authenticates the user before the request reaches Nginx. It is not as seamless as native SSO but it works.

    Next Steps

    Now that Plausible is running on your VPS, here are recommended follow-ups:

    • Harden access with fail2ban — Add a jail for /login brute-force attempts against Plausible's auth endpoint. Pair it with a long password policy for admin accounts.
    • Add uptime monitoring — Deploy Uptime Kuma to ping https://analytics.yourdomain.com every minute and alert on downtime. Losing events during an outage is unrecoverable.
    • Pipe events into your warehouse — Plausible's ClickHouse is directly queryable. Connect a BI tool (Metabase, Grafana, Superset) or export nightly snapshots into BigQuery / Snowflake for deeper analysis alongside product data.
    • Use the Stats API — Plausible exposes a JSON Stats API for building custom dashboards, embedding live visitor counts on your marketing site, or feeding metrics into Slack bots.
    • Compare against Umami — If you want a lighter stack, our Umami install guide walks through the alternative. Both are solid; the right choice depends on your scale and stack preferences.

    Skip the Manual Install — Get Plausible Pre-Configured
    >
    Our Analytics-Ready VPS plans come with Plausible Community Edition, ClickHouse, Postgres, and Nginx + TLS pre-configured. Deploy in 60 seconds and start tracking before your first coffee goes cold.
    >
    - Plausible CE latest stable pre-installed
    - ClickHouse and Postgres tuned for your plan's RAM
    - Nginx reverse proxy with Let's Encrypt SSL automated
    - Daily Postgres + ClickHouse backups to local disk
    - Custom-domain tracking script setup walkthrough
    >
    Deploy Your Analytics VPS Now — CloudCore Starter from €7.99/month.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket