Skip to main content

Postgres

CloudNativePG archives every WAL segment to the off-site bucket (postgres.backup.destinationPath) as soon as it is written, and takes a base backup daily (postgres.backup.schedule). Backups older than postgres.backup.retention are removed. That allows point-in-time recovery to any second in the window. Check:
Take one now (before upgrades):

Restore

Restore into a new cluster, check it, then point the platform at it. CloudNativePG never overwrites a running cluster.
  1. Stop writes: kubectl -n atoll scale deployment/atoll-server --replicas=0.
  2. Create the recovered cluster (targetTime is optional; without it the latest WAL is replayed):
  3. When it is healthy, switch the server: atoll.values.postgres.url to jdbc:postgresql://atoll-db-restored-rw.atoll.svc.cluster.local:5432/atoll and existingSecret to atoll-db-restored-app, then helmfile ... apply. The app user’s password is new; the old one is not needed.
  4. Archive the restored cluster to a new path before it is used in production (otherwise both write to atoll-db/): give it its own ObjectStore or a different serverName.
Rehearse this every few months.

Secrets

Export the Secrets that cannot be regenerated and keep them encrypted outside the cluster (age, sops, a password manager):
ATOLL_ENV_KEYS matters most: Postgres backups contain env vars encrypted with it.

Object storage

SeaweedFS replicates within the cluster (storage.replication: "001"), which protects against a failed disk or node, not against losing the site. Copy the bucket off-site nightly, for example with rclone in a CronJob (do the same for the users’ Files buckets and atoll-store-backups on the Files SeaweedFS, see storage.md):
Restore by running the same sync in the other direction into a fresh atoll bucket.

Registry

zot keeps its blobs in the SeaweedFS bucket atoll-registry, replicated like the atoll bucket. Add it to the off-site copy (a second rclone sync atoll:atoll-registry offsite:atoll-registry-backup, with the registry user’s keys from registry/zot-s3) if you want images back without redeploying. The platform’s own images come from GHCR, so the platform can be reinstalled without zot.

Cluster state

k3s snapshots etcd every 12 hours and keeps 5 (/var/lib/rancher/k3s/server/db/snapshots). To ship them off-site add to deploy/selfhost/k3s/config.yaml:
In practice a lost cluster is rebuilt faster from the helmfile than from etcd: reinstall k3s, re-create the Secrets from your export, run helmfile sync with postgres restored from backup (see above, bootstrap the atoll-db cluster from recovery), and copy the bucket back.