Deploy Plausible Analytics on Kubernetes: Self-Hosted Stack

Self-hosting website analytics often requires complex orchestration of separate transactional and analytical databases. This configuration deploys Plausible CE on Kubernetes with PostgreSQL for operational data and ClickHouse for analytics events, producing a GDPR-compliant, cookie-free analytics stack accessible at a local domain.
| Component | Type | Port | Role |
|---|---|---|---|
plausible | Namespace | - | Isolates all resources under plausible |
plausible-pg-pvc | PersistentVolumeClaim | - | 10 GB for PostgreSQL data |
plausible-ch-pvc | PersistentVolumeClaim | - | 20 GB for ClickHouse events |
plausible-pg-config | ConfigMap | - | PostgreSQL env vars |
plausible-pg-secret | Secret | - | PostgreSQL password |
plausible-ch-config | ConfigMap | - | ClickHouse env vars |
plausible-ch-secret | Secret | - | ClickHouse password |
plausible-ch-files | ConfigMap | - | config.xml and users.xml as mounted files |
plausible-app-config | ConfigMap | - | Plausible env vars (BASE_URL, DB URLs) |
plausible-app-secret | Secret | - | SECRET_KEY_BASE |
plausible-postgres | StatefulSet | 5432 | PostgreSQL 16: OLTP store for users and config |
plausible-postgres-service | Service (ClusterIP) | 5432 | Internal DNS only |
plausible-clickhouse | Deployment | 8123/9000 | ClickHouse: OLAP store for events |
plausible-clickhouse-service | Service (ClusterIP) | 8123/9000 | Internal DNS only |
plausible | Deployment | 8000 | App server with 3 init containers |
plausible-service | Service (ClusterIP) | 8000 | Internal: Ingress routes here |
nginx | IngressClass | - | Declares NGINX as default ingress class |
plausible-ingress | Ingress | 80 | Routes plausible.local to app service |
plausible-hpa | HorizontalPodAutoscaler | - | Scales Plausible pods from 1 to 3 replicas |
plausible-quota | ResourceQuota | - | Namespace resource cap |
plausible-limits | LimitRange | - | Per-container defaults |
plausible-postgres-netpol | NetworkPolicy | 5432 | PostgreSQL: Plausible pods only |
plausible-clickhouse-netpol | NetworkPolicy | 8123/9000 | ClickHouse: Plausible pods only |
plausible-app-netpol | NetworkPolicy | 8000 | Plausible: NGINX ingress only |
PostgreSQL stores users, sites, and goals, while ClickHouse stores every pageview for fast aggregation. The Plausible pod is the only component that talks to both databases, a constraint enforced by NetworkPolicies. Three sequential init containers ensure both databases are ready and migrations complete before the main application starts. NGINX Ingress forwards real client IPs for accurate geo data parsing.
openssl rand -hex 64, base64-encode it, and replace the placeholder in the plausible-app-secret manifest.kubectl get pods -n plausible and confirm all three pods show a status of Running.http://plausible.local in your browser and confirm the Plausible admin setup screen loads.http://plausible.local/api/health and confirm the JSON response shows healthy.This template configures a 24-resource Kubernetes stack running Plausible CE with PostgreSQL for operational data and ClickHouse for analytics events, exposed via NGINX Ingress with per-component ConfigMap, Secret, and NetworkPolicy isolation.