# Stalwart Mail Server — Backup & Restore Procedures ## Overview Stalwart stores all data in a RocksDB database mounted at `/opt/stalwart-mail` on a 20Gi encrypted hcloud volume (`hcloud-volumes-encrypted` storage class). ## Backup Strategy ### Option A: Hetzner Volume Snapshots (Recommended) Hetzner Cloud provides volume snapshots that capture the full encrypted volume state. #### Manual Snapshot via hcloud CLI ```bash # Get the volume ID bin/hcloud volume list | grep stalwart # Create a snapshot (works even while volume is mounted — RocksDB is crash-safe) bin/hcloud volume snapshot create --description "stalwart-backup-$(date +%Y%m%d)" ``` #### Scheduled Snapshots (Daily) Create a CronJob in Kubernetes to automate snapshots: ```yaml # Requires hcloud CLI and API token in a secret apiVersion: batch/v1 kind: CronJob metadata: name: stalwart-snapshot namespace: mail spec: schedule: "0 3 * * *" # 3 AM daily jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: hcloud-snapshot image: alpine:latest command: - /bin/sh - -c - | apk add --no-cache curl jq VOLUME_ID=$(curl -s -H "Authorization: Bearer $HCLOUD_TOKEN" \ https://api.hetzner.cloud/v1/volumes | \ jq -r '.volumes[] | select(.name | contains("stalwart")) | .id') curl -X POST -H "Authorization: Bearer $HCLOUD_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"description\": \"stalwart-auto-$(date +%Y%m%d)\"}" \ https://api.hetzner.cloud/v1/volumes/$VOLUME_ID/actions/create_snapshot env: - name: HCLOUD_TOKEN valueFrom: secretKeyRef: name: hcloud-credentials key: token ``` ### Option B: Filesystem-Level Backup Back up the data directory while Stalwart is paused or using a consistent snapshot. ```bash # Scale down Stalwart (brief downtime) kubectl scale deployment stalwart -n mail --replicas=0 # Exec into a temporary pod with the same PVC kubectl run backup-helper --image=alpine --restart=Never \ -n mail \ --overrides='{"spec":{"volumes":[{"name":"data","persistentVolumeClaim":{"claimName":"stalwart-data"}}],"containers":[{"name":"backup-helper","image":"alpine","command":["sleep","3600"],"volumeMounts":[{"name":"data","mountPath":"/opt/stalwart-mail"}]}]}}' # Copy data out kubectl cp mail/backup-helper:/opt/stalwart-mail ./stalwart-backup-$(date +%Y%m%d) # Clean up helper pod kubectl delete pod backup-helper -n mail # Restore Stalwart kubectl scale deployment stalwart -n mail --replicas=1 ``` ### Option C: Stalwart Admin API Backup (Config Only) Backup the configuration without downtime: ```bash # Backup config via Stalwart admin API curl -u admin:PASSWORD https://mail.paperclip.cloud/api/store/backup \ -o stalwart-config-backup-$(date +%Y%m%d).zip ``` ## Restore Procedures ### Restore from Volume Snapshot 1. **Create a new volume from the snapshot**: ```bash bin/hcloud volume create --name stalwart-restore --size 20 \ --snapshot --location fsn1 ``` 2. **Scale down Stalwart**: ```bash kubectl scale deployment stalwart -n mail --replicas=0 ``` 3. **Delete old PVC** (after backing up the PV name): ```bash PV_NAME=$(kubectl get pvc stalwart-data -n mail -o jsonpath='{.spec.volumeName}') kubectl delete pvc stalwart-data -n mail ``` 4. **Create PV pointing to restored volume**: ```bash RESTORED_VOLUME_ID= kubectl apply -f - <