PROJ-66 (Planned): kein App- oder Cron-Backup für /var/archivmail/store, Keyfile, PostgreSQL auf 131 und 132 vorhanden. Nutzer-Rückmeldung ergänzt: Infra-Ebene sichert bereits per Proxmox Backup Server + Sync auf Zweitserver, das entschärft den Off-Site-Blocker deutlich - verbleibende Kernlücke ist ein nie getesteter Restore, nicht das fehlende Backup-Ziel. Bitwarden- Keyfile-Escrow als zusätzlicher, von PBS unabhängiger Wiederherstellungsweg ergänzt. PROJ-65: Deploy-Agent hatte Status/QA-Ergebnisse bereits lokal geschrieben, aber noch nicht committed.
26 KiB
PROJ-66: Backup-Strategie für archivmail (Produktiv + Teilproduktiv)
Status: Planned Erstellt: 2026-07-04
Problem / Ausgangslage
Nachtrag (2026-07-04, nach Nutzer-Rückmeldung): Auf Infrastruktur-Ebene existiert bereits eine Sicherung: Die Container werden per Snapshot auf einen zweiten Server synchronisiert und zusätzlich per Proxmox Backup Server (PBS) gezogen. Das ist von innerhalb des Containers nicht sichtbar (läuft vom Proxmox-Host aus) — deshalb kam die ursprüngliche Prüfung unten ("kein Backup-Prozess") zu einem unvollständigen Bild. Das entschärft die zuvor als Blocker geführte Frage nach einem Off-Site-Ziel erheblich: PBS + Sync auf zweiten Server ist bereits eine physisch getrennte Sicherung.
Was das ändert und was offen bleibt, siehe Abschnitt "Bewertung der
Infra-Ebene" weiter unten. Der ursprüngliche Befund (App-Ebene: kein
pg_dump/rsync/Cron für archivmail selbst) bleibt als Kontext stehen, ist
aber durch die Infra-Sicherung teilweise bereits abgedeckt.
Verifizierter Ist-Stand (geprüft am 2026-07-04, beide Hosts)
Beide Server sind LXC-Container (systemd-detect-virt → lxc), das
zugrunde liegende Storage ist ein ZFS-Dataset auf dem Proxmox-Host
(zfs/data/subvol-1131-disk-0 bzw. -1132-disk-0), aber aus dem Container
heraus nicht als ZFS ansprechbar (kein zfs/zpool-Binary im Container,
kein Zugriff auf Host-Snapshots). Zff-Snapshots wären nur vom Proxmox-Host aus
möglich — das ist eine separate Maßnahme außerhalb der Kontrolle des
archivmail-Deploy-Prozesses und wird hier als Zusatzoption erwähnt, aber nicht
als alleinige Lösung behandelt (siehe Optionen unten).
Geprüft und nicht vorhanden:
crontab -l(root): leer auf beiden Hosts/etc/cron.d/: nurarchivmail(App-eigener Cron, PROJ-56c Purge/Reindex/OCR),e2scrub_all,sysstat— kein Backup-Eintrag/etc/cron.{daily,hourly,weekly}: nur Standard-Debian-Pakete (apt, dpkg, logrotate, man-db) — kein Backup-Skriptsystemctl list-timers: nur Standard-systemd/apt-Timer, kein Backup-Timer- LVM: kein
lvs/vgsim Container - Borg/Restic/rsnapshot/Bacula: nicht installiert
/var/backups/: enthält nur dpkg/apt-Housekeeping-Dateien, keine archivmail-Daten
Vorhanden, aber ungenutzt/nicht automatisiert:
pg_basebackup,pg_backupcluster(Debian-PostgreSQL-Standardtools) — installiert, aber kein Aufruf irgendwomanticore-backup— installiert, kein Aufruf irgendwo
Fazit: Bei Totalausfall eines der beiden Container (Hardware, Filesystem-
Korruption, versehentliches rm, Ransomware, fehlerhaftes Update) sind Store,
Keyfile und Datenbank unwiederbringlich verloren. Das betrifft aktuell
sowohl 131 (Produktiv) als auch 132 (teilproduktiv, ~51.000 Mails).
Aktuelle Datenmengen (Referenz für Aufwandsschätzung)
| Server | Store-Größe | DB | Config |
|---|---|---|---|
| 131 | 3,8 MB (frisch, PROJ-65-Migration) | n/a (Verbindungsproblem bei Check — Peer-Auth) | 23 KB |
| 132 | 6,9 GB (~51.000 Mails) | n/a (nicht separat geprüft) | — |
Store-Wachstum ist also unterschiedlich weit fortgeschritten; 132 hat den größeren produktiven Datenbestand trotz "Test"-Label.
Bewertung der Infra-Ebene (PBS + Server-Sync)
Container-/Snapshot-Backup auf Proxmox-Ebene sichert typischerweise das
komplette Root-Filesystem des LXC — d.h. /var/archivmail/store,
/etc/archivmail/keyfile, /etc/archivmail/config.yml, PostgreSQL-Datendir
und /var/log/archivmail/audit.log gemeinsam als ein Snapshot. Das löst
das in "Warum das kritisch ist" beschriebene Kern-Risiko (Store/Keyfile/DB
müssen zusammen gesichert werden) potenziell bereits vollständig, da alles im
selben Container liegt und in einem Snapshot landet — vorausgesetzt
PostgreSQL läuft ebenfalls im selben Container wie Store/Keyfile (zu
verifizieren, siehe offene Punkte unten).
Was dadurch (voraussichtlich) bereits erfüllt ist:
- Physische Trennung (AC 3) — zweiter Server + PBS sind eigene Infrastruktur.
- Gemeinsame Konsistenz von Store+DB+Keyfile+Config (AC 1) — ein Filesystem-Snapshot enthält zwangsläufig alle Dateien vom selben Zeitpunkt.
- Hardlink-Erhalt (AC 2) — ein Block-/Filesystem-Snapshot (ZFS/PBS) kopiert
keine Dateien einzeln, sondern sichert die Filesystem-Struktur inklusive
Inode-Referenzen — Hardlinks aus PROJ-65 bleiben dabei erhalten (anders als
bei einem naiven
cp -r, das dieses Ticket ursprünglich als Risiko für ein noch zu bauendes App-Backup benannt hatte).
Was weiterhin offen bleibt, auch mit PBS+Sync:
- PostgreSQL-Crash-Konsistenz: Ein Snapshot mitten im Betrieb ist für
PostgreSQL kein sauberes Backup wie
pg_dump, sondern entspricht einem Stromausfall-Szenario — PostgreSQL kommt damit über WAL-Replay beim nächsten Start i.d.R. wieder in einen konsistenten Zustand (das ist der Normalfall, für den WAL gebaut ist), aber das ist nicht dasselbe wie ein verifizierter, anwendungskonsistenter Dump. Sollte einmal getestet werden (Restore-Test, siehe unten), nicht nur angenommen. - Restore ist ungetestet — ein Backup, das nie zurückgespielt wurde, ist nicht verifiziert (gilt für PBS-Snapshots genauso wie für ein selbstgebautes rsync-Skript). Das ist unabhängig davon, wer das Backup zieht, weiterhin ein offener Punkt.
- Retention/DSGVO-Abgleich: Wie lange hält PBS die Snapshots vor, und ist das mit der DSGVO-Löschkonzeption (PROJ-50) abgestimmt? Muss geklärt werden, ist aber eine reine Konfigurationsfrage im PBS, kein neuer Code.
- Monitoring/Alerting: Läuft der PBS-Job zuverlässig durch, und gibt es eine sichtbare Warnung bei Ausfall? (Vermutlich ja, PBS hat eigenes Job-Monitoring — zu verifizieren, nicht Teil des archivmail-Codes.)
- Keyfile-Einzelkopie (Bitwarden): Zusätzlich zur PBS-Sicherung soll das Keyfile separat in Bitwarden hinterlegt werden (Nutzer-Entscheidung, 2026-07-04) — als unabhängiger Wiederherstellungsweg, falls PBS/Snapshot- Infrastruktur selbst nicht verfügbar ist. Details siehe eigener Abschnitt unten.
Auswirkung auf den Rest dieser Spec: Die unten stehenden Optionen A/B/C
und der App-eigene rsync+cron-Ansatz sind jetzt Ergänzung, nicht mehr
alleinige Lösung — vor allem für den Fall, dass ein anwendungskonsistenter
pg_dump zusätzlich zur PBS-Snapshot-Sicherung gewünscht wird (schnellerer,
selektiver Restore einzelner Tabellen, unabhängig von Snapshot-Zeitpunkten).
Die kritischste verbleibende Lücke ist nicht mehr "kein Backup-Ziel",
sondern "Restore nie getestet" — das bleibt so oder so zu tun, egal
welche Backup-Quelle (PBS oder App-Skript) im Ernstfall genutzt wird.
Warum das kritisch ist
- Datenverlust ohne Backup ist bei einem Mail-Archivsystem ein Compliance-Vorfall, nicht nur ein IT-Vorfall — GoBD verlangt Verfügbarkeit archivierter Mails über die Aufbewahrungsfrist.
- Store, Keyfile und PostgreSQL-Metadaten sind nur gemeinsam nutzbar:
- Store ohne DB-Metadaten: Dateien vorhanden, aber keine Zuordnung zu Mail/Tenant/Betreff/Datum → praktisch nicht auffindbar.
- Keyfile ohne Store: irrelevant, nichts zu entschlüsseln.
- DB ohne Keyfile: Metadaten vorhanden, aber Mail-Inhalte nicht mehr entschlüsselbar → GoBD-Anforderung "Lesbarmachung" verletzt.
- Ein Backup, das nur eine dieser drei Komponenten sichert, ist wertlos.
- PROJ-65 hat gerade Tenant-Hardlink-Verzeichnisse (
store/tenant_<id>/) eingeführt. Ein Backup-Tool, das Hardlinks nicht erhält (z.B.cp -r, naivesscp -r), würde bei jedem Backup den Speicherbedarf im Backup-Ziel vervielfachen (pro Tenant eine Vollkopie statt eines Hardlinks) — kein Datenverlust, aber Speicherplatz-Explosion und potenziell Backup-Jobs, die wegen vollem Zielverzeichnis fehlschlagen.
Backup-Strategie-Optionen
Option A — rsync + cron, konsistenter Snapshot via kurzem Stop (empfohlen als erster Schritt)
Ablauf pro Lauf (nachts, Zeitfenster mit wenig Traffic wählen, ggf. an PROJ-56-Last-Entzerrung orientieren):
systemctl stop archivmail(Backend stoppen — Store/DB werden während des Kopiervorgangs nicht verändert; Frontend kann laufen bleiben, da es nur liest, aber optional auch stoppen für saubere Konsistenz)pg_dump -Fc archivmail > backup.dump(Custom-Format, komprimiert, erlaubt selektiven Restore einzelner Tabellen)rsync -aH --delete /var/archivmail/store/ <ziel>/store/—-Hist Pflicht, sonst werden Tenant-Hardlinks aus PROJ-65 zu Vollkopien aufgelöstcp /etc/archivmail/keyfile <ziel>/keyfile(getrennt verschlüsselt/ abgesichert, siehe unten)cp /etc/archivmail/config.yml <ziel>/config.ymlcp /var/log/archivmail/audit.log <ziel>/audit.log.$(date +%F)(Append- Only-Charakter erhalten — Datei nicht überschreiben, sondern datiert kopieren, damit historische Audit-Nachweise auch bei Log-Rotation auf dem Quellsystem nicht verloren gehen)systemctl start archivmail- Health-Check nach Neustart (Backend ✓ läuft, wie im Standard-Deploy-Workflow)
- Manticore-Index: niedrige Priorität, aus Store+DB per
archivmail reindexrekonstruierbar — kein Backup nötig, ggf. optionalmanticore-backupfür schnelleren Recovery-Pfad (Reindex von 51k Mails kann je nach OCR-Last dauern)
Vorteil: Downtime ist kurz (Stop → Kopieren der geänderten Blöcke via rsync inkrementell → Start), einfach zu verstehen, kein neues Tooling nötig außer rsync/cron (beide bereits vorhanden). Nachteil: Downtime existiert (wenn auch kurz bei inkrementellem rsync nach dem ersten vollen Lauf).
Option B — PITR / kontinuierliche Konsistenz ohne Stop (vollständige Lösung, später)
- PostgreSQL: WAL-Archiving + Basisbackup (
pg_basebackup) für Point-in-Time-Recovery statt Downtime beim Dump. - Store: Da Store append-only/content-adressiert ist (Dateien werden nach
Schreiben nie verändert, nur neue hinzugefügt oder per GoBD-Purge gelöscht),
ist ein Live-rsync ohne Stop grundsätzlich risikoarm — die einzige
Inkonsistenz-Gefahr ist ein Mail-Datensatz, der in der DB bereits committed
ist, aber dessen Store-Datei noch nicht vollständig geschrieben wurde (Race
zwischen Storage-Write und DB-Commit). Das lässt sich durch Reihenfolge
Store-zuerst-dann-DB im Schreibpfad (falls nicht schon so implementiert —
bei mailarchiv-architect erfragen) und/oder einen Reconciliation-Check nach
dem Restore (PROJ-52
archivmail reconcile) abfedern statt durch Downtime. - Aufwand deutlich höher (WAL-Archiv-Ziel, Retention der WAL-Segmente, mehr bewegliche Teile) — als Phase 2 vorschlagen, nicht als ersten Schritt.
Option C — Proxmox-Host-Snapshots (ZFS)
Da beide Hosts LXC-Container auf Proxmox mit ZFS-Backing sind, sind
Host-seitige ZFS-Snapshots oder Proxmox-Backup-Server-Jobs eine sinnvolle
Ergänzung (schnelle Rollback-Möglichkeit bei OS-/Config-Fehlern), aber
kein Ersatz für anwendungskonsistente Backups: Ein ZFS-Snapshot mitten im
pg_dump-losen Normalbetrieb sichert PostgreSQL nicht transaktionskonsistent
(außer Postgres nutzt selbst WAL + fsync korrekt, was bei ZFS-Snapshots auf
Blockebene in der Praxis meist funktioniert, aber nicht ausdrücklich
validiert wurde). Empfehlung: als Zusatzschicht einplanen, aber erfordert
Zugriff auf den Proxmox-Host, der nicht Teil dieses Deploy-Agenten-Scopes
ist — separates Ticket/Absprache mit dem Infrastruktur-Verantwortlichen für
den Proxmox-Host nötig.
Empfehlung
Phase 1 (dieses Ticket, pragmatisch): Option A — rsync+cron mit kurzem Stop, tägliches Backup auf ein Off-Container-Ziel (siehe Off-Site unten). Deckt das eigentliche Risiko (Totalverlust ohne jegliches Backup) sofort ab.
Phase 2 (späteres Ticket): Option B (PITR) wenn Downtime-Fenster zum Problem wird (z.B. wegen wachsendem Store auf 132), plus Option C als zusätzliche Sicherheitsschicht in Absprache mit Proxmox-Host-Admin.
Backup-Ziel: On-Site vs. Off-Site
- On-Site-only ist nicht ausreichend: Beide Produktivsysteme (131, 132) laufen vermutlich auf derselben Proxmox-Host-Infrastruktur — ein Host-Ausfall (Hardware, Ransomware, Fehlkonfiguration) könnte beide Systeme UND ein On-Site-Backup-Ziel gleichzeitig treffen, wenn es auf demselben Host/Storage liegt.
- Empfehlung: Backup-Ziel auf physisch getrennter Infrastruktur (zweiter Host, NAS außerhalb des Proxmox-Clusters, oder Cloud-Storage mit Verschlüsselung — Cloud nur wenn DSGVO-konform vertraglich abgesichert, siehe Verschlüsselung unten).
- Mindestens: 3-2-1-Prinzip anstreben (3 Kopien, 2 verschiedene Medien, 1
Off-Site) — für den pragmatischen ersten Schritt reicht 2 Kopien (Produktiv
- 1 Backup-Ziel off-site) mit klarer Dokumentation, dass das noch nicht vollständig 3-2-1 ist.
Verschlüsselung des Backups selbst
Das Backup enthält Keyfile UND verschlüsselte Mails zusammen — sobald beide am selben Ort liegen, ist der Verschlüsselungsschutz des Stores faktisch aufgehoben, wenn das Backup-Ziel kompromittiert wird. Anforderungen:
- Transport: rsync über SSH (ohnehin Standard) oder explizit
rsync -e ssh, niemals unverschlüsseltes Protokoll (FTP, unverschlüsseltes NFS über öffentliches Netz). - At-Rest am Backup-Ziel: Wenn das Backup-Ziel als weniger vertrauenswürdig
gilt als der Produktivserver (z.B. NAS mit mehr Admin-Zugriffsberechtigten,
Cloud-Storage), muss das Backup-Ziel selbst verschlüsselt sein — entweder
Ziel-Filesystem-Verschlüsselung (LUKS) oder Backup-Tool mit eingebauter
Verschlüsselung (z.B.
resticmit Repository-Passwort — als Phase-2-Option evaluieren, da es außerdem Deduplizierung/Versionierung mitbringt). - Keyfile separat behandeln: Empfehlung, das Keyfile-Backup zusätzlich getrennt vom Store-Backup aufzubewahren (anderer Zugriffspfad/anderes Passwort) — erschwert Angreifern, die nur das Backup-Ziel kompromittieren, den vollen Zugriff. Mindestens: restriktive Dateirechte (0600, root-only) auch im Backup.
- Backup-Skript selbst darf Zugangsdaten (SSH-Key fürs Backup-Ziel) nicht im Klartext in world-readable Cron-Dateien ablegen (analog zu PROJ-64 Datei-Permissions-Härtung).
Keyfile-Escrow in Bitwarden (Nutzer-Entscheidung, 2026-07-04)
Zusätzlich zur PBS-/Sync-Sicherung wird das Keyfile als unabhängige Kopie in Bitwarden hinterlegt — für den Fall, dass die Snapshot-/PBS-Infrastruktur selbst nicht verfügbar oder kompromittiert ist.
- Zugriffsbeschränkung: Eigene Bitwarden-Collection/Ordner, nur für Personen mit Restore-Berechtigung sichtbar — nicht die allgemeine Organisations-Vault. Das Keyfile entschlüsselt das gesamte Archiv aller Mandanten, ist der höchstwertige Secret im System.
- Format: Secure Note mit Base64-kodiertem Keyfile-Inhalt (32 Byte roh → base64 fürs Notizfeld), plus Metadaten (welcher Server/welche Installation, Erstellungsdatum, wer hat's zuletzt geprüft).
- Kein Ersatz für Zugriffskontrolle: Bitwarden-Zugriff muss genauso ernst genommen werden wie root-Zugriff auf den Produktivserver (2FA Pflicht, Zugriffsprotokoll wenn Bitwarden das bietet).
- Rotation/Prüfung dokumentieren: Wer Zugriff hat und wann zuletzt verifiziert wurde, dass der Bitwarden-Eintrag noch mit dem aktiven Keyfile übereinstimmt (relevant falls das Keyfile jemals rotiert wird — aktuell nicht vorgesehen, aber für die Zukunft dokumentieren).
- Kein Blocker für die restlichen ACs — unabhängig von PBS/App-Backup umsetzbar, kleiner Zusatzschritt (Bitwarden-Eintrag anlegen, kein Code).
Aufbewahrungsdauer / Rotation
- Vorschlag: Tägliche Backups, Rotation nach Generationen-Prinzip:
- 7 tägliche Backups
- 4 wöchentliche Backups (z.B. jeweils Sonntag)
- 6 monatliche Backups
- Wichtig: Rotation der Backup-Kopien ist unabhängig von der GoBD-Aufbewahrungsfrist der Mails selbst (PROJ-51 Retention-Kategorien) — eine gelöschte/abgelaufene Mail in Produktion kann in einem älteren Backup noch enthalten sein. Das ist im Rahmen der GoBD-Löschkonzeption (PROJ-50, DSGVO-Löschersuchen) zu dokumentieren: Backups mit personenbezogenen Daten, die in Produktion bereits DSGVO-gelöscht wurden, dürfen nicht unbegrenzt aufbewahrt werden → Backup-Rotation muss kurz genug sein, dass gelöschte Daten nach spätestens N Rotationszyklen auch aus alten Backups verschwinden (Abstimmung mit Datenschutzbeauftragtem/Nutzer nötig, kein rein technisches Thema).
Restore-Prozess (muss dokumentiert UND getestet sein)
Kein Backup ohne verifizierten Restore-Prozess. Vorschlag Runbook-Struktur
(Stil analog docs/MIGRATION_RUNBOOK.md):
- Zielserver vorbereiten (frisches Debian oder vorhandener Server im Wartungsmodus, archivmail-Dienste gestoppt).
- Store wiederherstellen:
rsync -aH <backup>/store/ /var/archivmail/store/(Hardlinks bleiben erhalten). - Keyfile wiederherstellen:
cp <backup>/keyfile /etc/archivmail/keyfile, Rechte prüfen (0600, root:root). - Config wiederherstellen:
cp <backup>/config.yml /etc/archivmail/config.yml. - PostgreSQL wiederherstellen:
pg_restore -d archivmail <backup>/backup.dump(auf leere, frisch angelegte DB). - Audit-Log wiederherstellen (informativ, kein Funktionsbestandteil):
/var/log/archivmail/audit.logaus dem letzten Backup-Stand kopieren. - Dienste starten, Health-Check (Backend ✓, Frontend ✓ wie im Standard-Deploy-Workflow).
- Verifikation (Pflicht, nicht optional):
archivmail reconcilelaufen lassen (PROJ-52) — Zählvergleich Store-Dateien vs. DB-Einträge muss aufgehen.- Stichprobe: 3-5 zufällige Mails über die UI öffnen und lesbar entschlüsseln lassen (beweist Keyfile+Store+DB passen zusammen).
archivmail reindexausführen, Suche testen (Manticore wird aus 1+3 rekonstruiert).
- Restore-Ergebnis (Mail-Zahl, Zeitstempel, Dauer) dokumentieren — analog zum Migrations-Runbook-Prinzip "Zählen, Prüfen, Belegen".
Regelmäßiger Restore-Test: Ein Backup, das nie zurückgespielt wurde, ist nicht verifiziert. Empfehlung: mindestens vierteljährlich einen Restore auf einen isolierten Test-Container durchführen (nicht auf 131/132!) und Schritt 8 durchlaufen.
Monitoring / Alerting für den Backup-Job selbst
Größtes Risiko bei Cron-Backups: Job schlägt still fehl, niemand merkt es, bis der Ernstfall eintritt (siehe PROJ-58-Lehre: "Cron-Zeilen fehlten wochenlang trotz aktivem Code, weil es niemand automatisch prüfte").
Anforderungen:
- Backup-Skript muss Exit-Code aller Teilschritte prüfen (rsync, pg_dump, cp) und bei Fehler nicht die Rotation der alten (guten) Backups anstoßen (sonst wird ein gutes altes Backup durch ein fehlgeschlagenes überschrieben).
- Log-Datei pro Lauf mit Zeitstempel, Ergebnis, Dauer, Größe.
- Alerting: minimal ein "Backup-Alter"-Check, der z.B. vom bestehenden Health-Check-Mechanismus oder Dashboard (PROJ-17-Metriken-Anlehnung) mitgeprüft wird — "letztes erfolgreiches Backup älter als 26h" → sichtbarer Warnzustand (Dashboard-Badge oder E-Mail/Webhook, je nachdem was im System bereits an Alerting existiert; falls nichts existiert, ist das ein Teil dieses Tickets: minimal ein Cron-Check-Skript, das eine Markerdatei mit Zeitstempel nach erfolgreichem Lauf schreibt und ein zweiter Cron-Job/Health-Endpoint das Alter dieser Datei prüft).
User Stories
- Als Betreiber möchte ich, dass Store, Keyfile und DB-Metadaten täglich automatisiert und konsistent gesichert werden, damit ein Server-Totalausfall nicht zu unwiederbringlichem Mail-Verlust führt.
- Als Betreiber möchte ich, dass ein fehlgeschlagener Backup-Lauf sichtbar wird (nicht erst beim Restore-Versuch auffällt), damit ich rechtzeitig eingreifen kann.
- Als GoBD-Verantwortlicher möchte ich, dass ich im Audit-Fall belegen kann, dass Backups vorhanden, aktuell und restorebar sind.
- Als Datenschutzbeauftragter möchte ich, dass DSGVO-Löschungen (PROJ-50) nicht durch unbegrenzt aufbewahrte Backups unterlaufen werden.
Acceptance Criteria
- Es existiert ein dokumentiertes, automatisiert laufendes Backup (Cron oder systemd-Timer) auf 131 UND 132, das Store, Keyfile, PostgreSQL-DB und config.yml konsistent zueinander sichert.
- Das Backup-Tool erhält nachweislich Hardlinks im Store (Test: Backup-Größe
nach PROJ-65-Tenant-Hardlinks entspricht nicht der Summe aller
Tenant-Kopien, sondern der tatsächlichen Store-Größe — Stichprobe via
du --apparent-sizevs.dubzw.statLink-Count-Check nach Restore). - Backup liegt auf einem vom Produktivsystem physisch getrennten Ziel (nicht im selben Proxmox-Host/-Storage wie 131/132, sofern das ohne zusätzliche Host-Beschaffung machbar ist — sonst als bekannte Einschränkung dokumentieren).
- Backup-Daten (insbesondere Keyfile-Kopie und Store-Kopie zusammen) sind am Zielort verschlüsselt oder das Ziel ist gleichwertig abgesichert wie der Produktivserver.
- Rotation/Retention ist implementiert und lässt Backups nicht unbegrenzt wachsen; Retention ist kurz genug, um DSGVO-Löschungen nicht dauerhaft zu unterlaufen (Zeitraum mit Nutzer/Datenschutzbeauftragtem abgestimmt).
- Ein vollständiger Restore wurde mindestens einmal auf einem isolierten
Testsystem durchgeführt und mit
archivmail reconcile+ Stichproben- Entschlüsselung verifiziert; Ergebnis ist dokumentiert. - Es gibt einen sichtbaren Alarm-/Warnmechanismus, wenn der letzte erfolgreiche Backup-Lauf älter als ein definiertes Schwellenwert-Fenster ist (z.B. 26h bei täglichem Backup).
- Ein Backup-Runbook (analog
docs/MIGRATION_RUNBOOK.md) existiert unterdocs/BACKUP_RESTORE_RUNBOOK.mdmit Schritt-für-Schritt-Anleitung für Backup, Restore und Verifikation. update.sh-Vollständigkeits-Check: Falls das Backup-Skript/der Cron-Job als Datei unterdeploy/im Repo gepflegt wird, synctupdate.shdiese Datei nachweislich mit aus (Lehre aus PROJ-58, siehe Deploy-Vollständigkeits- Check in den devops-deploy-Regeln) — sonst existiert das Skript nur lokal und geht beim nächsten Server-Neuaufsatz verloren.- Keyfile-Kopie liegt zugriffsbeschränkt in Bitwarden (Secure Note, eigene Collection, nur Restore-Berechtigte) — unabhängig von PBS/App-Backup.
- PBS-/Sync-Sicherung verifiziert: Dokumentiert ist, was genau gesichert wird (welcher Container/welche Pfade), wie lange PBS die Snapshots vorhält, und dass mindestens ein Restore aus einem PBS-Snapshot erfolgreich getestet wurde (nicht nur aus einem App-eigenen Backup, falls beide existieren).
Edge Cases
- Server-Totalausfall (131 oder 132): Restore auf neuem/wiederhergestelltem Container muss laut Runbook in angemessener Zeit möglich sein (Ziel-RTO definieren, z.B. < 4h für 132 mit 51k Mails — abhängig von Reindex-Dauer).
- Backup-Job schlägt fehl, ohne dass es auffällt: durch Monitoring/ Alerting (siehe oben) abgedeckt — Testfall: Backup-Skript künstlich zum Scheitern bringen (z.B. Zielverzeichnis vollschreiben) und prüfen, ob der Alarm tatsächlich auslöst.
- Restore-Test schlägt fehl: Reconcile zeigt Lücken → Ursache muss vor Produktivnutzung des Backups geklärt werden (z.B. Backup lief während aktiven Schreibvorgangs ohne Stop-Schritt → Konsistenzproblem im Backup-Skript selbst beheben).
- Backup-Ziel läuft voll: Rotation muss dies verhindern; zusätzlich
Disk-Space-Check vor jedem Lauf (analog
df -h-Diagnose-Befehl im devops-deploy-Skill) mit Abbruch + Alarm statt partiellem/korruptem Backup. - PROJ-65-Hardlinks nach Restore: Nach Restore prüfen, dass
Tenant-Hardlink-Struktur (
store/tenant_<id>/) wiederhergestellt ist und nicht zu doppeltem Speicherverbrauch auf dem Zielsystem führt. - Gleichzeitiger Schreibzugriff während Backup (Option A mit Stop): Kurzer Downtime-Fenster einplanen und in Betriebszeiten kommunizieren (SMTP- Empfang während Stop puffert sich ggf. beim Absender/Relay, sollte mit mailarchiv-architect abgeklärt werden, ob eingehende Mails während Backend- Stop verloren gehen könnten oder ob es einen Retry-Mechanismus gibt).
- 132 ist "teilproduktiv": Muss von Anfang an mit derselben Priorität wie 131 behandelt werden, nicht nachrangig als "nur Testserver" — bereits im Ticket-Titel und in den ACs berücksichtigt (beide Server, nicht nur 131).
Aufwandseinschätzung
Durch die vorhandene PBS+Sync-Infrastruktur verschiebt sich der Schwerpunkt von "Backup-Ziel schaffen" zu "vorhandenes Backup verifizieren + gezielt ergänzen":
- Phase 0 (klein, zuerst): Bitwarden-Keyfile-Escrow anlegen (kein Code, <1h). Dokumentieren, was PBS/Sync konkret sichert und mit welcher Retention (Abstimmung mit demjenigen, der PBS betreibt — vermutlich kein archivmail-Code-Zugriff nötig, eher ein Gespräch/Screenshot der PBS-Job-Konfiguration). Geschätzt 1-2h.
- Phase 1 (Restore-Verifikation, wichtigster verbleibender Schritt): Ein
echter Restore-Test aus einem PBS-Snapshot auf einen isolierten
Test-Container, durchlaufen mit
archivmail reconcile+ Stichproben- Entschlüsselung (siehe Restore-Prozess oben). Deckt auf, ob die PostgreSQL-Crash-Konsistenz in der Praxis reicht oder ob doch ein zusätzlicherpg_dumpnötig ist. Geschätzt 2-4h (abhängig davon, wie schnell ein Testsystem für den Restore verfügbar ist). - Phase 2 (nur falls Phase 1 Lücken zeigt): App-eigenes rsync+cron+pg_dump (Option A) als Ergänzung, falls PBS-Snapshots allein nicht ausreichen (z.B. weil Retention zu kurz für Compliance ist, oder PITR-Granularität gebraucht wird). Aufwand wie ursprünglich geschätzt, 4-6h.
- Phase 3 (optional, später): PITR/WAL-Archiving, restic/borg-Migration — nur falls Phase 1/2 einen konkreten Bedarf dafür aufzeigen.
Offene Entscheidung vor Implementierung von Phase 1: Steht ein isolierter Test-Container für den Restore-Test zur Verfügung (nicht 131/132 selbst)?
Nicht Teil dieses Tickets
- Implementierung selbst (dieses Ticket liefert nur die Spec, Status "Planned" — Implementierung erst nach Freigabe).
- Konfiguration/Änderung der PBS-Jobs selbst (liegt außerhalb des archivmail-Deploy-Scopes, eigener Verantwortungsbereich).
- Proxmox-Host-seitige ZFS-Snapshot-Konfiguration (separates Thema, anderer Verantwortungsbereich/Zugriff).