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?
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
| Scenario | Plausible Cloud | Google Analytics 4 | Self-Hosted Plausible (VPS) |
|---|---|---|---|
| Monthly cost (100K views) | $19/mo | Free | €7.99/mo |
| Monthly cost (1M views) | $69/mo | Free | €7.99/mo |
| Monthly cost (10M views) | $269/mo | Free | €7.99/mo |
| Cookie banner required? | No | Yes | No |
| Data retention | Unlimited | 2-14 months | Unlimited (your disk) |
| Data ownership | Shared with Plausible | 100% yours | |
| SQL access to raw data | No | BigQuery export (paid) | Yes (direct ClickHouse) |
| Custom domain tracker | Paid add-on | No | Yes (free) |
| Funnels | Business plan | Yes (complex) | Yes (included) |
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:
ssh root@your-server-ipStep 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.
sudo apt update && sudo apt upgrade -yExpected output (abbreviated):
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:
sudo rebootThen 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:
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.gpgAdd the Docker repository:
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/nullInstall Docker Engine and the Compose plugin:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginVerify the install:
docker --version
docker compose versionExpected output:
Docker version 27.3.1, build ce12230
Docker Compose version v2.29.7Add 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):
sudo usermod -aG docker $USERFor 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.
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:
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):
git fetch --tags
git checkout v2.1.5 # or whatever the current stable tag is — check the releases pageThe repository layout you will work with:
/opt/plausible/
├── compose.yml # the Docker Compose definition
├── .env.example # template for environment variables
├── reverse-proxy/ # optional Caddy-based reverse proxy configs
└── README.mdStep 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:
openssl rand -base64 48Example output (yours will be different — that is the point):
f8s9Q2vN5mK3pR7xL4jH6bZ1cW8yD0tE5aG9iU2oP4qS7rX3zV6nMRun 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:
cp .env.example .env
nano .envAt minimum, set the following values:
# The canonical public URL where Plausible will be served
BASE_URL=https://analytics.yourdomain.comPhoenix session signing key (48 bytes, base64)
SECRET_KEY_BASE=f8s9Q2vN5mK3pR7xL4jH6bZ1cW8yD0tE5aG9iU2oP4qS7rX3zV6nMTOTP encryption key (48 bytes, base64) — DIFFERENT value from SECRET_KEY_BASE
TOTP_VAULT_KEY=m2H7kP9wR3qT6uY1iO5aS8dF4gJ0lZ6vX2cN9bV3nM5xQ7zK1pLDatabase 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_dbDisable public registration once your admin account is created
DISABLE_REGISTRATION=invite_onlySMTP 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=trueKey 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 fromSECRET_KEY_BASE.DATABASE_URL— Connection string for the metadata Postgres (users, sites, configuration). The compose file creates this service asplausible_db.CLICKHOUSE_DATABASE_URL— Connection string for the events ClickHouse (every page view and custom event). The compose file creates this asplausible_events_db.DISABLE_REGISTRATION— Set toinvite_onlyafter 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.
Ctrl+O, Enter, Ctrl+X).Step 5: Review the docker-compose.yml
Open the compose file to understand what is about to run:
cat compose.ymlThe three services that matter:
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: - .envplausible_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.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:
docker compose up -dExpected output:
[+] Running 4/4
✔ Network plausible_default Created
✔ Container plausible-plausible_db-1 Started
✔ Container plausible-plausible_events_db-1 Started
✔ Container plausible-plausible-1 StartedFirst-time startup runs database migrations for both Postgres and ClickHouse, which typically takes 20-40 seconds. Follow the logs:
docker compose logs -f plausibleWait for the line:
[info] Running PlausibleWeb.Endpoint with cowboy 2.10.0 at :::8000 (http)
[info] Access PlausibleWeb.Endpoint at http://localhost:8000Press Ctrl+C to stop following logs. Verify the HTTP endpoint responds locally:
curl -I http://127.0.0.1:8000Expected output:
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
https:// or www., e.g. yourdomain.com)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:
docker compose restart plausibleThis 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:
<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#routingscript.outbound-links.js— automatically tracks outbound link clicksscript.file-downloads.js— tracks clicks on links to.pdf,.zip,.dmg, etc.script.tagged-events.js— enables manual custom events viadata-attributesscript.exclusions.js— allows excluding specific URLs from trackingscript.compat.js— Internet Explorer / older browser fallback
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:
<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
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
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:
sudo apt install -y nginx certbot python3-certbot-nginxCreate the site configuration:
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:
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 nginxCertbot sets up automatic renewal via a systemd timer. Verify:
sudo systemctl list-timers | grep certbotThe 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.
docker compose exec -T plausible_db pg_dump -U postgres plausible_db | \
gzip > /opt/plausible/backups/postgres-$(date +%F).sql.gzClickHouse 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:
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/clickhouseAutomating with Cron
Add to /etc/cron.daily/plausible-backup:
#!/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 -deleteMake executable:
sudo chmod +x /etc/cron.daily/plausible-backupShip 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:
cd /opt/plausible
git fetch --tags
git checkout v2.2.0 # or whichever is current
docker compose pull
docker compose up -dMigrations run automatically when the plausible container starts. Check the logs:
docker compose logs -f plausibleLook 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:
# 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:
<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.
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
| Problem | Cause | Solution |
|---|---|---|
502 Bad Gateway from Nginx | Plausible container not running or bound to wrong port | docker 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 dashboard | Tracking snippet data-domain mismatch, or script blocked | Open 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 Origin | Visitor browser blocks analytics.yourdomain.com | Follow Step 12 to proxy the script through your main domain. |
| ClickHouse disk fills up | Event retention is unlimited by default | Old 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 startup | Secret too short or not base64 | Regenerate with openssl rand -base64 48 and paste the entire output into .env. |
Can't register — registration is disabled | First-run gate or DISABLE_REGISTRATION active | On fresh install, set DISABLE_REGISTRATION=false, restart, register, then set back to invite_only. |
| IPv6 connectivity issues | Docker bridge not bridging IPv6 traffic correctly | Add "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 site | Page views take up to 30 seconds to propagate through the ingestion pipeline on a fresh install | Reload 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 invite | SMTP credentials wrong or port blocked | Test 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:
docker compose logs -f plausibleAll services:
docker compose logs -fLast 100 lines of ClickHouse (useful when events are not appearing):
docker compose logs --tail=100 plausible_events_dbFAQ
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
/loginbrute-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.comevery 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.