# Backup & Restore Runbook – archivmail Bezug: `features/PROJ-66-backup-strategie.md` (Spec + Entscheidungsverlauf), `docs/GOBD_DSGVO_CHECKLIST.md` Punkt 7 (Löschsperre) und 15 (Mandantentrennung). Ziel: belegen können, dass ein Totalausfall von Store, Keyfile oder PostgreSQL nicht zu unwiederbringlichem Mail-Verlust führt — und dass ein Restore im Ernstfall tatsächlich funktioniert, nicht nur theoretisch existiert. Gilt für: `archivmail backup`/`archivmail restore` (PROJ-66, App-eigenes CLI-Backup) und ergänzend die Proxmox Backup Server (PBS) + Sync-auf- Zweitserver-Sicherung auf Infrastruktur-Ebene. ## Grundsatz Store, Keyfile und PostgreSQL-Metadaten sind **nur gemeinsam** nutzbar: - Store ohne DB: Dateien vorhanden, aber keine Zuordnung zu Mail/Tenant. - Keyfile ohne Store: irrelevant, nichts zu entschlüsseln. - DB ohne Keyfile: Metadaten da, Mail-Inhalte nicht mehr lesbar (GoBD-Verstoß). Ein Backup, das nur eine dieser drei Komponenten sichert, ist wertlos. Ein Backup, das nie zurückgespielt wurde, ist nicht verifiziert — siehe "Regelmäßiger Restore-Test" unten. ## Zwei unabhängige Sicherungsebenen 1. **Infrastruktur-Ebene (PBS + Sync auf Zweitserver)** — läuft vom Proxmox-Host aus, sichert den kompletten Container (Store+Keyfile+ Config+PostgreSQL-Datendir+Audit-Log in einem Snapshot). Von innerhalb des Containers nicht sichtbar/steuerbar. Siehe Memory `project_backup_infra_pbs` für CLI-Befehle (`vzdump`, `pct restore`). 2. **App-eigenes Backup (`archivmail backup`/`restore`)** — ergänzt Ebene 1 um einen anwendungskonsistenten `pg_dump` (statt reinem Crash-Consistency- Snapshot) und einen selektiven, von PBS unabhängigen Restore-Weg. Keine der beiden Ebenen ersetzt die andere. Ein vollständiger Restore-Test sollte mindestens einmal **beide** Wege durchlaufen haben (siehe unten). ## Backup erstellen ```bash archivmail backup --config /etc/archivmail/config.yml --dest --keep 14 ``` - `` MUSS auf einem vom Produktivsystem physisch getrennten Ziel liegen (zweiter Host, NAS, o.ä.) — siehe PROJ-66-Spec, Abschnitt "Backup-Ziel: On-Site vs. Off-Site". Ein Backup auf derselben Platte schützt nicht vor Hardware-Ausfall. - Schreibt `//`: `postgres.dump` (`pg_dump -Fc`), `store/` (Hardlink-erhaltende Kopie, PROJ-65-Tenant-Ordner bleiben ohne Speicherplatz-Verdopplung erhalten), `keyfile`, `config.yml`, `audit.log` (best-effort). - `--keep N` behält die letzten N Backup-Verzeichnisse, löscht ältere — **nur nach erfolgreichem Lauf**. Ein fehlgeschlagener Lauf lässt den partiellen Ordner stehen und rotiert nichts weg (Diagnose-Möglichkeit, kein Verlust eines guten alten Backups). - Cron-Aktivierung: `deploy/cron.d/archivmail` enthält eine auskommentierte Beispielzeile. Erst aktivieren, wenn ein konkretes `--dest`-Ziel feststeht. ## Keyfile-Escrow (Bitwarden) Zusätzlich zum Backup: das Keyfile als unabhängige Kopie in Bitwarden hinterlegen (Secure Note, eigene Collection mit eingeschränktem Zugriff — das Keyfile entschlüsselt das **gesamte Archiv aller Mandanten**). ```bash cat /etc/archivmail/keyfile # → Wert 1:1 in eine neue Bitwarden Secure Note kopieren, Metadaten # ergänzen (Server/Installation, Datum, wer hinterlegt hat). ``` Zweck: unabhängiger Wiederherstellungsweg, falls PBS/Snapshot-Infrastruktur selbst nicht verfügbar ist. Ersetzt nicht das App-Backup — beide parallel pflegen. Bei künftiger Keyfile-Rotation (aktuell nicht vorgesehen) den Bitwarden-Eintrag im selben Schritt aktualisieren. ## Restore durchführen **Vorbereitung:** 1. Zielsystem: frischer Server/Container oder vorhandenes System im Wartungsmodus. `archivmail`/`archivmail-web` müssen gestoppt sein — `archivmail restore` stoppt/startet die Dienste NICHT selbst. 2. Backup-Verzeichnis identifizieren: `//`. **Durchführung:** ```bash systemctl stop archivmail archivmail-web archivmail restore --config /etc/archivmail/config.yml \ --source / [--force] ``` - Ohne `--force`: bricht ab, wenn `store_path`/Keyfile bereits Inhalt haben — Schutz gegen versehentliches Überschreiben eines laufenden Systems. `--force` nur auf einem bewusst freigeräumten/frischen Zielsystem nutzen. - `--skip-db`: überspringt `pg_restore`, falls die Datenbank bereits separat wiederhergestellt wurde (z.B. via PBS-Snapshot der DB-Ebene). - Stellt Store (Hardlinks erhalten), Keyfile, Config und PostgreSQL (`pg_restore --clean --if-exists`) wieder her. Gibt am Ende die Pflicht-Verifikationsschritte aus (siehe unten). **Verifikation (Pflicht, nicht optional):** ```bash systemctl start archivmail archivmail-web # Health-Check wie im Standard-Deploy-Workflow (Backend ✓, Frontend ✓) archivmail reconcile --days 7 # PROJ-52: Zählvergleich Store vs. DB muss aufgehen archivmail reindex # Manticore aus Store+DB neu aufbauen # Stichprobe: 3-5 zufällige Mails über die UI öffnen und lesbar entschlüsseln # lassen — beweist, dass Keyfile+Store+DB zueinander passen. ``` Restore-Ergebnis (Mail-Zahl, Zeitstempel, Dauer, welche Verifikationsschritte liefen) dokumentieren — Prinzip "Zählen, Prüfen, Belegen" wie im Migrations-Runbook. ## Restore aus einem PBS-Snapshot (Infrastruktur-Ebene) Auf dem Proxmox-**Host** (nicht im Container): ```bash pct restore :backup/ct// --storage ``` Restored als neuer Container mit `` — der Quell-Container bleibt unangetastet. Danach dieselbe Verifikation wie oben (`reconcile`, `reindex`, Stichprobe) im neuen Container durchführen. PostgreSQL kam dabei aus einem Crash-Consistency-Snapshot, nicht aus einem `pg_dump` — WAL-Replay beim Start ist der Normalfall, sollte aber beim Test explizit beobachtet werden (`journalctl -u postgresql` auf Recovery-Meldungen prüfen). ## Regelmäßiger Restore-Test Ein Backup, das nie zurückgespielt wurde, ist nicht verifiziert. Empfehlung: mindestens vierteljährlich einen vollständigen Restore auf einen isolierten Test-Container durchführen (**nicht auf 131/132!**) — einmal über `archivmail restore` (App-Backup) und mindestens einmal über `pct restore` (PBS-Snapshot), jeweils mit vollständiger Verifikation. Bislang (Stand 2026-07-05) wurde noch kein Restore-Test durchgeführt — das ist die kritischste offene Lücke in der Backup-Strategie, nicht das Fehlen eines Backup-Ziels. ## Rotation vs. DSGVO-Löschung Backup-Rotation (`--keep N`, bzw. PBS-Retention) ist unabhängig von der GoBD-Aufbewahrungsfrist der Mails selbst (PROJ-51). Eine in Produktion bereits DSGVO-gelöschte Mail (PROJ-50) kann in einem älteren Backup noch enthalten sein. Rotation muss kurz genug sein, dass gelöschte Daten nach spätestens N Zyklen auch aus Backups verschwinden — Zeitraum mit Datenschutzbeauftragtem/Nutzer abstimmen, kein rein technisches Thema. ## Monitoring / Alerting (noch offen) Größtes Risiko bei Cron-Backups: der Job schlägt still fehl, niemand merkt es bis zum Ernstfall (Lehre aus PROJ-58: Cron-Zeilen fehlten wochenlang trotz aktivem Code). Aktuell **nicht gebaut**: ein sichtbarer Alarm, wenn das letzte erfolgreiche Backup älter als ein Schwellenwert ist. Bis dahin: Log-Datei des Backup-Cron-Jobs (`/var/log/archivmail/backup.log`, sobald der Cron aktiviert ist) manuell im Rahmen der regulären Betriebs-Checks prüfen. ## Verweis - `features/PROJ-66-backup-strategie.md` — vollständige Spec, Optionsabwägung, QA-Ergebnisse. - `docs/MIGRATION_RUNBOOK.md` — Vorbild für den "Zählen, Prüfen, Belegen"-Stil. - Memory `project_backup_infra_pbs` — PBS/Sync-Infrastruktur-Details, `vzdump`/`pct restore`-Befehle. - Memory `project_132_teilproduktiv` — 132 ist kein reiner Testserver, Backup-Sorgfalt gilt dort genauso wie auf 131.