
This article provides a guide to install Plausible CE on AlmaLinux VPS using Docker Compose, then puts it behind Nginx with HTTPS from Let’s Encrypt.
What is Plausible CE?
Plausible CE stands for Plausible Community Edition.
It is the free, self-hosted version of Plausible Analytics, a privacy-focused alternative to Google Analytics. Instead of sending your website analytics data to a third-party analytics provider, you install Plausible CE on AlmaLinux VPS or server and keep the data under your control.
Plausible describes CE as the free, self-hosted, AGPL-licensed release of Plausible Analytics. Their managed cloud service is the paid hosted version, while CE is for users who want to run and maintain it themselves.
In practical terms, Plausible CE gives you:
- Website traffic analytics
- Page views, visitors, referrers, countries, devices, browsers, and operating systems
- Goal and event tracking
- A lightweight tracking script
- Cookie-free analytics
- A cleaner, simpler dashboard than Google Analytics
- Full self-hosting control
It is commonly used by website owners, agencies, SaaS companies, privacy-focused businesses, and hosting providers that want analytics without the heavier tracking model of traditional ad-tech platforms.
A typical Plausible CE deployment runs with:
- Plausible application
- PostgreSQL database
- ClickHouse analytics/event database
- Docker Compose
- Reverse proxy such as Nginx, Caddy, or Traefik
The official Plausible CE repository notes that Docker and Docker Compose are required, ClickHouse requires SSE 4.2 or NEON CPU support, and at least 2 GB RAM is recommended.
The main difference is:
- Plausible Cloud = hosted and maintained by Plausible
- Plausible CE = installed, hosted, updated, secured, and backed up by you
So, Plausible CE is best understood as a self-hosted, privacy-friendly web analytics platform for people who want Google Analytics-style insight without giving up control of their analytics data.
Plausible CE’s current official community setup is Docker-based. Its repo lists Docker and Docker Compose as prerequisites, requires a CPU with SSE 4.2 or NEON support because of ClickHouse, and recommends at least 2 GB RAM. The current quick-start branch shown by the Plausible CE repo is v3.2.1.
Assumptions used below:
- Plausible domain: analytics.example.com
- Server OS: AlmaLinux 9 or AlmaLinux 10
- Public ports: 80 and 443 handled by Nginx
- Plausible internal port: 8000, bound only to 127.0.0.1
- Install directory: /opt/plausible-ce
Replace analytics.example.com with your real domain.
[pricing_comparison_almalinux]
Install Plausible CE on AlmaLinux VPS with Nginx Reverse Proxy
To install Plausible CE on AlmaLinux VPS with Nginx reverse proxy, follow the steps below:
-
Point DNS to your VPS
Create an
Arecord:analytics.example.com -> YOUR_SERVER_IPV4
Optional IPv6:
analytics.example.com -> YOUR_SERVER_IPV6
Wait until DNS resolves:
dig +short analytics.example.com
or:
ping analytics.example.com
Do not continue with Let’s Encrypt until the domain points to the VPS.
-
Update AlmaLinux
SSH into your VPS as root or a sudo user:
ssh root@YOUR_SERVER_IP
Update packages:
dnf update -y dnf install -y curl wget git nano unzip tar dnf-plugins-core openssl
Reboot if the kernel was updated:
reboot
Reconnect after reboot.
-
Set the hostname
Optional but recommended:
hostnamectl set-hostname analytics.example.com
Verify:
hostnamectl
-
Install Docker Engine and Docker Compose plugin
Docker’s official CentOS/RHEL-family instructions recommend installing from Docker’s RPM repository and installing
docker-ce,docker-ce-cli,containerd.io,docker-buildx-plugin, anddocker-compose-plugin.Remove conflicting container packages if present:
dnf remove -y podman buildah runc
Add Docker’s repo:
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
Install Docker:
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Enable and start Docker:
systemctl enable --now docker
Verify:
docker --version docker compose version systemctl status docker --no-pager
Test Docker:
docker run --rm hello-world
-
Install Nginx and Certbot
dnf install -y epel-release dnf install -y nginx certbot python3-certbot-nginx
Enable Nginx:
systemctl enable --now nginx
Verify:
nginx -v systemctl status nginx --no-pager
-
Configure the firewall
If
firewalldis enabled:systemctl enable --now firewalld firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload firewall-cmd --list-all
Do not expose Plausible’s internal port
8000publicly. -
Handle SELinux for Nginx reverse proxying
On AlmaLinux, SELinux is usually enabled. Nginx may be blocked from proxying to a local backend unless this boolean is enabled:
setsebool -P httpd_can_network_connect 1
Verify SELinux status:
getenforce
-
Clone Plausible CE
Create the install directory:
mkdir -p /opt cd /opt
Clone the current Plausible CE branch shown in the official quick start:
git clone -b v3.2.1 --single-branch https://github.com/plausible/community-edition plausible-ce cd /opt/plausible-ce
The official quick start uses this same clone pattern, then creates a
.envfile withBASE_URLandSECRET_KEY_BASE.Check files:
ls -la
You should see files like:
compose.yml clickhouse/ README.md LICENSE
-
Create the Plausible environment file
Create
.env:cd /opt/plausible-ce nano .env
Add:
BASE_URL=https://analytics.example.com SECRET_KEY_BASE=REPLACE_WITH_GENERATED_SECRET HTTP_PORT=8000
Generate a secure secret:
openssl rand -base64 48
Paste the generated value into
.env.Example:
BASE_URL=https://analytics.example.com SECRET_KEY_BASE=Q6c5xHhV7oYx7q9Z7REPLACE_THIS_WITH_YOUR_REAL_GENERATED_VALUE HTTP_PORT=8000
BASE_URLandSECRET_KEY_BASEare required. Plausible’s configuration page saysBASE_URLhas no default, andSECRET_KEY_BASEmust be at least 64 bytes; it also shows generating it withopenssl rand -base64 48.Set safe permissions:
chmod 600 .env
-
Create a Docker Compose override for localhost-only access
By default, this guide puts Nginx in front of Plausible. So Plausible should listen only on localhost, not directly on the public internet.
Create:
nano compose.override.yml
Add:
services: plausible: ports: - "127.0.0.1:8000:8000"This means:
Host 127.0.0.1:8000 -> Plausible container port 8000
Do not use:
- "0.0.0.0:8000:8000"
unless you intentionally want the app exposed directly.
-
Start Plausible CE
From
/opt/plausible-ce:docker compose pull docker compose up -d
Check running containers:
docker compose ps
Check logs:
docker compose logs -f
You should eventually see the Plausible app start successfully.
Test locally from the server:
curl -I http://127.0.0.1:8000
Expected result should include an HTTP response from Plausible, commonly
200,302, or similar. -
Create the Nginx reverse proxy config
Create an Nginx server block:
nano /etc/nginx/conf.d/plausible.conf
Add:
server { listen 80; listen [::]:80; server_name analytics.example.com; access_log /var/log/nginx/plausible.access.log; error_log /var/log/nginx/plausible.error.log; location / { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 60s; proxy_send_timeout 60s; } }Test Nginx:
nginx -t
Reload:
systemctl reload nginx
Visit:
http://analytics.example.com
At this stage HTTP should work.
-
Install Let’s Encrypt SSL
Run Certbot:
certbot --nginx -d analytics.example.com
Choose the redirect-to-HTTPS option when prompted.
Test renewal:
certbot renew --dry-run
Check the generated HTTPS config:
nginx -t systemctl reload nginx
Visit:
https://analytics.example.com
-
Create your first Plausible user
Register plausible ce account Open:
https://analytics.example.com
Create the first admin user through the web interface.
After creating the first user, I recommend disabling open registration.
Edit
.env:cd /opt/plausible-ce nano .env
Add:
DISABLE_REGISTRATION=true
Restart Plausible:
docker compose up -d
Plausible CE’s configuration docs list
DISABLE_REGISTRATIONas an available registration control with values includingtrue,false, andinvite_only. -
Configure email sending
Plausible can run without email, but password resets, invites, email verification, and reports need SMTP or an email provider.
Add SMTP-related values to
.env. Example:MAILER_EMAIL=analytics@example.com SMTP_HOST_ADDR=smtp.example.com SMTP_HOST_PORT=587 SMTP_USER_NAME=analytics@example.com SMTP_USER_PWD=YOUR_SMTP_PASSWORD SMTP_HOST_SSL_ENABLED=false SMTP_RETRIES=2
Then restart:
docker compose up -d
Check logs:
docker compose logs -f plausible
Plausible CE docs state that transactional emails such as account activation and password reset are sent through SMTP by default, with other services such as Postmark, Mailgun, Mandrill, or SendGrid also supported.
-
Add your first website in Plausible
Add website in plausible Inside the Plausible dashboard:
- Click Add website.
- Enter your site domain, for example:
example.com
- Copy the tracking script.
- Add it before
on your website.
The snippet will look similar to:
<!-- Privacy-friendly analytics by Plausible --> <script async src="https://analytics.example.com/js/pa-iev8zYK-aOK0OR2L0DwJR.js"></script> <script> window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}}; plausible.init() </script>Then visit your website and confirm real-time traffic appears in Plausible.
-
Optional: proxy the tracking script through your main website domain
This is different from the Nginx reverse proxy used to host Plausible itself.
Example:
Plausible dashboard: https://analytics.example.com Main website: https://example.com Proxied script: https://example.com/js/script.js Proxied event endpoint: https://example.com/api/event
Plausible’s Nginx proxy guide describes proxying the script and event endpoint through your own domain, with locations for
/js/script.jsand/api/event.On your main website’s Nginx config, add:
location = /js/script.js { proxy_pass https://analytics.example.com/js/script.js; proxy_set_header Host analytics.example.com; proxy_buffering on; } location = /api/event { proxy_pass https://analytics.example.com/api/event; proxy_set_header Host analytics.example.com; proxy_buffering on; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; }Then change your tracking code to:
For custom events, use the proxied endpoint if needed.
-
Useful management commands
Go to the install directory first:
cd /opt/plausible-ce
Start:
docker compose up -d
Stop:
docker compose down
Restart:
docker compose restart
View status:
docker compose ps
View logs:
docker compose logs -f
View only Plausible logs:
docker compose logs -f plausible
Pull updated images:
docker compose pull docker compose up -d
-
Backups
Plausible CE uses PostgreSQL for user/config data and ClickHouse for analytics events. Its configuration docs state that PostgreSQL stores user data and ClickHouse stores analytics data.
Create a backup directory:
mkdir -p /opt/backups/plausible chmod 700 /opt/backups/plausible
Back up PostgreSQL
cd /opt/plausible-ce docker compose exec -T plausible_db pg_dump -U postgres plausible_db > /opt/backups/plausible/plausible_db_$(date +%F).sql
Back up Docker volumes
List volumes:
docker volume ls | grep plausible
Create a compressed backup of Plausible-related volumes:
cd /opt/plausible-ce docker run --rm \ -v plausible-ce_db-data:/volume/db-data:ro \ -v plausible-ce_event-data:/volume/event-data:ro \ -v /opt/backups/plausible:/backup \ alpine \ tar czf /backup/plausible_volumes_$(date +%F).tar.gz -C /volume .
Volume names may differ. Confirm them with:
docker volume ls
-
Set up automatic backup cron
Create a script:
nano /usr/local/sbin/backup-plausible.sh
Add:
#!/bin/bash set -euo pipefail BACKUP_DIR="/opt/backups/plausible" APP_DIR="/opt/plausible-ce" DATE="$(date +%F-%H%M%S)" mkdir -p "$BACKUP_DIR" cd "$APP_DIR" docker compose exec -T plausible_db pg_dump -U postgres plausible_db > "$BACKUP_DIR/plausible_db_$DATE.sql" docker run --rm \ -v plausible-ce_db-data:/volume/db-data:ro \ -v plausible-ce_event-data:/volume/event-data:ro \ -v "$BACKUP_DIR":/backup \ alpine \ tar czf "/backup/plausible_volumes_$DATE.tar.gz" -C /volume . find "$BACKUP_DIR" -type f -mtime +14 -delete
Make executable:
chmod +x /usr/local/sbin/backup-plausible.sh
Test:
/usr/local/sbin/backup-plausible.sh ls -lh /opt/backups/plausible
Create cron:
crontab -e
Add:
15 2 * * * /usr/local/sbin/backup-plausible.sh >/var/log/plausible-backup.log 2>&1
-
Update Plausible CE
Check the Plausible CE GitHub releases before upgrading.
Basic update process:
cd /opt/plausible-ce docker compose down git fetch --tags git checkout vNEW_VERSION docker compose pull docker compose up -d docker compose logs -f
Always back up before upgrading:
/usr/local/sbin/backup-plausible.sh
-
Harden the installation
Recommended production settings:
chmod 600 /opt/plausible-ce/.env chown -R root:root /opt/plausible-ce
Make sure Plausible is not publicly exposed:
ss -tulpn | grep 8000
You want to see something like:
127.0.0.1:8000
not:
0.0.0.0:8000
Check open firewall services:
firewall-cmd --list-services
Expected:
http https ssh
Consider restricting SSH to your IP and using SSH keys.
-
Troubleshooting
-
Nginx returns 502 Bad Gateway
Check Plausible:
cd /opt/plausible-ce docker compose ps docker compose logs --tail=100 plausible curl -I http://127.0.0.1:8000
Check Nginx errors:
tail -f /var/log/nginx/plausible.error.log
If SELinux is enforcing, run:
setsebool -P httpd_can_network_connect 1
-
Certbot fails
Check DNS:
dig +short analytics.example.com
Check ports:
firewall-cmd --list-services
Check Nginx config:
nginx -t
Retry:
certbot --nginx -d analytics.example.com
-
Plausible says the domain or URL is wrong
Verify
.env:cat /opt/plausible-ce/.env
Make sure:
BASE_URL=https://analytics.example.com
Then restart:
cd /opt/plausible-ce docker compose up -d
-
Containers keep restarting
View logs:
cd /opt/plausible-ce docker compose logs -f
Common causes:
Invalid SECRET_KEY_BASE Wrong BASE_URL Not enough RAM ClickHouse startup failure Bad compose.override.yml indentation
-
-
Final verification checklist
Run:
curl -I https://analytics.example.com docker compose -f /opt/plausible-ce/compose.yml -f /opt/plausible-ce/compose.override.yml ps certbot certificates
Confirm:
https://analytics.example.com loads First admin user exists Registration is disabled Tracking script is installed on your site Real-time visits appear in Plausible Backups are working Certbot dry-run succeeds Plausible port 8000 is bound only to 127.0.0.1
Conclusion
You now know how to install Plausible CE on AlmaLinux VPS.











