How to restore Plausible from backups

This guide shows you how to restore the Plausible databases after data loss. PostgreSQL and ClickHouse restore independently; restore both to a consistent point when possible.

Prerequisites

  • kubectl access to the kup6s cluster.

  • For PostgreSQL: the S3 bucket backups-plausible-kup6s (fsn1) with barman backups.

  • For ClickHouse: a Longhorn backup of the volume data-plausible-clickhouse-0.

Stop the app

Suspend ArgoCD self-heal and scale the app down so no writes occur during the restore.

kubectl -n argocd patch application plausible-app-c85c5f8b --type merge -p '{"spec":{"syncPolicy":{"automated":null}}}'
kubectl scale deploy plausible -n plausible --replicas=0

Restore PostgreSQL

Follow the fleet-wide CNPG recovery procedure — see the CNPG deployment documentation for the full runbook. In short: create a new CNPG Cluster with bootstrap.recovery pointing at the plausible-postgres-backup ObjectStore, verify, then swap the app’s DATABASE_URL secret reference or rename the cluster.

If you only need to roll back data (not the cluster), restore into a scratch cluster and copy with pg_dump/pg_restore:

PRIMARY=$(kubectl get cluster -n plausible plausible-postgres -o jsonpath='{.status.currentPrimary}')
kubectl exec -n plausible $PRIMARY -c postgres -- psql -U postgres -c "DROP DATABASE plausible WITH (FORCE)"
kubectl exec -n plausible $PRIMARY -c postgres -- psql -U postgres -c "CREATE DATABASE plausible OWNER plausible"
kubectl exec -i -n plausible $PRIMARY -c postgres -- pg_restore -U postgres -d plausible --no-owner --role=plausible < dump.file

Restore ClickHouse

The ClickHouse volume is backed up crash-consistently by Longhorn.

  1. Scale the StatefulSet down: kubectl scale sts plausible-clickhouse -n plausible --replicas=0.

  2. In the Longhorn UI, restore the desired backup of data-plausible-clickhouse-0 to a new volume.

  3. Create a PV/PVC pair for the restored volume named data-plausible-clickhouse-0 (delete the old PVC first), following the Longhorn static-rebind recipe used in the Mailu dovecot migration.

  4. Scale the StatefulSet back up and check SELECT count() FROM plausible_events_db.events_v2.

ClickHouse replays its write-ahead state on start; a crash-consistent volume loses at most the last unflushed inserts.

Resume

kubectl scale deploy plausible -n plausible --replicas=1
kubectl -n argocd patch application plausible-app-c85c5f8b --type merge -p '{"spec":{"syncPolicy":{"automated":{"prune":true,"selfHeal":true}}}}'
curl -s https://stats.cloud.kup.tirol/api/health

The health endpoint must report ok for postgres, clickhouse, sessions, and sites_cache.