docs(dr): tabletop drill 2026-06-03 - findings against DISASTER_RECOVERY

Kalter Lesetest gegen das Bare-Metal-Szenario aus DR.md Phase 0 bis 5,
mit referenzierten Runbooks (SERVICES_RECOVERY, RESTORE_MATRIX,
SECRETS_MAP, RESTORE_HANDBOOK, EXTERNAL_DEPENDENCIES) und Compose-Ankern
(ops/komodo, traefik).

23 Findings mit Severity, Repo-Datei + Zeile, Fix-Vorschlag pro Punkt.
1x CRITICAL (Unraid-Flash-Restore ohne laufenden Host), 11x HIGH, 8x MED,
3x LOW.

Schwerpunkte:
- Bare-Metal-Operator-Workstation als DR-Voraussetzung nicht dokumentiert
- Henne-Ei: KOMODO_* externe Notiz vs. Vaultwarden-Reihenfolge
- Externe Docker-Netze fehlen in DR.md Phase 4 Stufe 1
- borg-ui-Container als impliziter Borg-Client im Bare-Metal-Bootstrap
- Nextcloud-Restore-Skript ist da, ist aber noch nie real gelaufen (X-1)

Keine produktiven Pfade beruehrt, kein Container gestartet, keine
Skripte ausgefuehrt - reiner Doku-Drill.
This commit is contained in:
2026-06-03 15:48:44 +02:00
parent 4b96d13510
commit 7a513e9fc8
+472
View File
@@ -0,0 +1,472 @@
# DR Tabletop Drill - 2026-06-03
Trockenlauf gegen `docs/DISASTER_RECOVERY.md` Phase 0 bis 5 plus referenzierte
Runbooks (`SERVICES_RECOVERY.md`, `RESTORE_MATRIX.md`, `SECRETS_MAP.md`,
`RESTORE_HANDBOOK.md`, `EXTERNAL_DEPENDENCIES.md`).
Szenario: Bare-Metal-Ausfall. Unraid-Host und alle lokalen Festplatten sind
weg. Operator hat: Laptop, Hetzner-Account, Vaultwarden-Export, Repo-Doku.
Soft-Recovery (Host laeuft, Appdata futsch) ist eine Teilmenge dieser
Findings.
Methode: kalter Lesetest. Kein Container gestartet, keine Skripte
ausgefuehrt. Jeder Befund ist mit Repo-Datei und Zeile belegt. Spekulative
"vielleicht unklar"-Befunde sind weggelassen.
Severity:
- **CRITICAL** - blockiert Wiederanlauf, ohne Workaround nicht loesbar
- **HIGH** - blockiert eine Phase, Workaround moeglich aber undokumentiert
- **MED** - kostet Zeit oder fuehrt zu vermeidbarem Fehler
- **LOW** - Konsistenz / Stil
## Zusammenfassung
| ID | Phase | Severity | Thema |
|---|---|---|---|
| P0-1 | 0 | HIGH | Brueckenpfad Windows-Clone -> frischer Unraid-Host fehlt |
| P0-2 | 0 | HIGH | GitHub-Mirror-Zugang im DR ist nicht eigenstaendig dokumentiert |
| P1-1 | 1 | CRITICAL | Unraid-Flash-Restore: kein dokumentierter Extract-Pfad ohne laufenden Host |
| P1-2 | 1 | MED | Unraid-OS-Flash-Restore-Test laut Matrix nie real getestet |
| P2-1 | 2 | HIGH | KOMODO_* externe Operator-Notiz ist Pflichtquelle, Existenz nicht verifizierbar |
| P2-2 | 2 | HIGH | DR.md Phase 4 vs. SERVICES_RECOVERY.md Bootstrap-Reihenfolge widerspruechlich |
| P2-3 | 2 | MED | `homelab_smtp_password.txt` fehlt in DR.md Phase 2.6.1 |
| P2-4 | 2 | MED | `n8n_encryption_key.txt` fehlt in DR.md Phase 2.6.1 |
| P2-5 | 2 | LOW | Monitoring-/Filebrowser-Secrets fehlen in DR.md Phase 2.6.1 |
| P3-1 | 3 | HIGH | Borg-Client ohne `borg-ui`-Container ist nicht dokumentiert |
| P3-2 | 3 | HIGH | Borg-Passphrase-Bootstrap aus Offline-Sicherung nicht als expliziter Schritt |
| P3-3 | 3 | MED | Hetzner-Maintenance-Key aus Vaultwarden ist Henne-Ei im Bare-Metal |
| P4-1 | 4 | HIGH | Externe Docker-Netze in DR.md Phase 4 Stufe 1 nicht erwaehnt |
| P4-2 | 4 | HIGH | Cloudflare-LE-Rate-Limit-Risiko bei verlorenem `letsencrypt`-State |
| P4-3 | 4 | MED | `traefik/dynamic/*` als Phase-4-Pre-Check fehlt in der Reihenfolge |
| P4-4 | 4 | HIGH | Authelia "frische Postgres ohne Dump"-Pfad nicht beschrieben |
| P4-5 | 4 | LOW | Gitea in Stufe 2 hinter Postgres ist faktisch nicht noetig (SQLite) |
| P4-6 | 4 | HIGH | Komodo-Mongo Passwort-Lockout-Risiko bei restauriertem Datadir |
| P4-7 | 4 | MED | Komodo `extra_hosts` mit hardgecodeter LAN-IP bricht bei IP-Wechsel |
| P4-8 | 4 | HIGH | Stack-ENV-Wiederherstellung in Komodo praktisch nur manueller UI-Eintrag |
| P5-1 | 5 | LOW | Smoke-Tests in Phase 5 weniger streng als RESTORE_MATRIX |
| P5-2 | 5 | MED | Kein Verifikationspunkt fuer App-zu-DB-Verbindung nach Stack-ENV-Restore |
| X-1 | uebergreifend | HIGH | Nextcloud-Restore-Skript ist da, aber noch nie real ausgefuehrt |
## Phase 0 - Repo-Zugang
### P0-1 (HIGH) - Brueckenpfad Windows-Clone -> frischer Unraid fehlt
`docs/DISASTER_RECOVERY.md:88-93` listet als Repo-Quellen: GitHub-Mirror,
lokaler Bare-Clone, lokaler Arbeits-Clone. `SERVICES_RECOVERY.md:67-68`
nennt den lokalen Operator-Clone unter `G:\Gitea_Clone\homelab-infra\` als
Vorzug.
Luecke: der Pfad "wie kommt der Windows-Clone auf einen frisch installierten
Unraid-Host" ist nicht beschrieben. Implizit: SMB-Share, USB-Stick, scp ueber
LAN. Aber auf einem frisch aufgesetzten Unraid existiert noch keine
funktionierende SMB-Konfiguration; SSH-Key vom Operator-PC ist nicht
vorbereitet.
Vorschlag: Zwei Saetze in `DISASTER_RECOVERY.md` Phase 0 ergaenzen, wie der
Operator-Clone konkret zum Host kommt (USB-Stick + `mkdir -p
/mnt/user/services/homelab-infra && rsync -a` aus Operator-Windows-PC, oder
direkt vom GitHub-Mirror per `git clone https://github.com/...` auf dem
Unraid-Host).
### P0-2 (HIGH) - GitHub-Mirror-Zugang im DR
`SECRETS_MAP.md:42` sagt, der GitHub-Push-Mirror-PAT liegt in den
Gitea-Mirror-Settings persistent unter `/mnt/user/services/gitea/data`.
`EXTERNAL_DEPENDENCIES.md:18` nennt den Mirror als `michaelkaleschke-spec/
homelab-infra` und betont "privater" Push-Mirror.
Luecke: Wenn der Mirror **privat** ist, scheitert ein anonymer `git clone`
im DR-Bootstrap. Es gibt keine dokumentierte Notfall-Quelle fuer einen
Read-PAT/SSH-Key, der lokal beim Operator (nicht in Gitea, nicht im Repo)
verfuegbar ist.
Vorschlag in `EXTERNAL_DEPENDENCIES.md`: entweder explizit dokumentieren,
dass der Mirror lesend `Public` ist (DR-fit), oder einen Read-PAT in der
Vaultwarden-/Offline-Notiz neben der Borg-Passphrase als Bootstrap-Voraussetzung
benennen.
## Phase 1 - Unraid und Shares
### P1-1 (CRITICAL) - Unraid-Flash-Restore ohne laufenden Host
`docs/DISASTER_RECOVERY.md:107` sagt: "Primaere lokale/off-site
Restore-Quelle fuer die bestehende Flash-Konfiguration ist das
Borg-Artefakt `unraid-flash-config.tar.gz` aus
`/mnt/user/backups/borg/dumps/latest`."
Henne-Ei: der Pfad ist auf den verlorenen Shares oder auf Hetzner. Hetzner-
Zugriff braucht einen funktionierenden Linux-Host mit Borg-Client und
Passphrase. Im Bare-Metal-Fall ist genau das nicht da. RESTORE_MATRIX.md
Tier 1 Zeile `Unraid OS Flash` (`docs/RESTORE_MATRIX.md:29`) sagt nur "Unraid
USB Flash Creator / neuer Boot-Stick" - das beschreibt die Stick-Erzeugung,
nicht den Extract des Borg-Artefakts.
Operativ: Operator braucht einen Laptop mit Borg-Client + Passphrase +
SSH-Key fuer die Hetzner-Storage-Box. Das ist eine **separat zu pflegende
Operator-Workstation-Voraussetzung** und ist in keinem Repo-Dokument als
DR-Vorbedingung gelistet.
Vorschlag: In `EXTERNAL_DEPENDENCIES.md` oder `DISASTER_RECOVERY.md`
Abschnitt 3 als Pflichtposten aufnehmen: "Operator-Laptop mit installiertem
Borg-Client, SSH-Key fuer Hetzner und Zugriff auf die offline gesicherte
Passphrase". Inklusive Test, dass der Operator den Extract tatsaechlich
durchfuehren kann.
### P1-2 (MED) - Unraid-OS-Flash-Restore-Test nie gelaufen
`docs/RESTORE_MATRIX.md:140` Spalte "Letzter Restore-Test" fuer Unraid OS
Flash: `-` (kein Test). Das ist die Grundlage fuer Phase 1 und ist nie als
Smoke verifiziert. Empfehlung: einmaliger Test, der die Tar-Archiv-Struktur
gegen die erwarteten Flash-Pfade prueft (kein echter Boot-Test noetig).
## Phase 2 - Secrets und Stack-ENV
### P2-1 (HIGH) - KOMODO_* externe Operator-Notiz als Pflichtquelle
`docs/SECRETS_MAP.md:132,138-143` macht den Komodo-Sonderfall klar: die
KOMODO_*-Secrets sind aus dem eigenen Mongo-Dump nicht rekonstruierbar,
solange Komodo nicht laeuft. Quellen: Vaultwarden ODER externe Notiz.
Im Bare-Metal-Fall ist Vaultwarden in DR.md Phase 4 Stufe 4, Komodo in
Phase 4 Stufe 3. Damit ist die **externe Operator-Notiz** die einzige
Pflichtquelle in der Reihenfolge.
Luecke: ob diese Notiz wirklich existiert und die 5 Werte
(KOMODO_SECRET_KEY, KOMODO_WEBHOOK_SECRET, KOMODO_JWT_SECRET,
KOMODO_MONGO_PASSWORD, KOMODO_PERIPHERY_PASSKEY) enthaelt, ist in keinem
Repo-Dokument bestaetigt. Die Borg-Passphrase ist als "Operator-Bestaetigung
2026-05-26" dokumentiert; eine analoge Bestaetigung fuer die KOMODO_*-Notiz
fehlt.
Vorschlag: gleiche Form wie Borg-Passphrase - eine Zeile in
`EXTERNAL_DEPENDENCIES.md` "Komodo-Stack-ENV-Notiz offline gesichert,
Operator-Bestaetigung YYYY-MM-DD".
### P2-2 (HIGH) - Reihenfolgen-Inkonsistenz DR vs. SERVICES_RECOVERY
`docs/SERVICES_RECOVERY.md:102` (Stufe C, Komodo-Bootstrap): "Vaultwarden
(sobald restauriert), externe Operator-Notiz, oder Komodo-Mongo-Dump (nur
wenn Mongo separat bereits gestartet ...)".
`docs/DISASTER_RECOVERY.md:247-301` (Phase 4): Stufe 3 = Komodo, Stufe 4 =
Vaultwarden.
Wenn ein Leser sich an DR.md Phase 4 haelt, ist Vaultwarden nach Komodo
fertig. Aber SERVICES_RECOVERY.md Stufe C setzt Vaultwarden als optionale
Vorab-Quelle voraus. Ohne externe Notiz heisst das praktisch: Komodo kann
nicht starten. Die Konsequenz steht nirgendwo explizit in DR.md.
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 Stufe 3 einen Hinweisblock
ergaenzen: "KOMODO_*-Werte muessen vor Stufe 3 aus externer Notiz oder
einer in Stufe 2 voraus gezogenen Vaultwarden-Instanz vorliegen. Default-
Pfad: externe Notiz."
### P2-3 (MED) - `homelab_smtp_password.txt` fehlt in DR.md 6.1
`docs/SECRETS_MAP.md:20` listet `/mnt/user/appdata/secrets/
homelab_smtp_password.txt` fuer Vaultwarden-SMTP. In `DISASTER_RECOVERY.md`
Abschnitt 6.1 (`docs/DISASTER_RECOVERY.md:136-151`) ist sie nicht
aufgefuehrt. Vaultwarden startet ohne, kann aber keine Einladungs-/
Benachrichtigungs-Mails versenden. Klein, aber unsichtbarer Folgefehler im
Familien-Onboarding-Pfad.
### P2-4 (MED) - `n8n_encryption_key.txt` fehlt in DR.md 6.1
`docs/SECRETS_MAP.md:58` listet `/mnt/user/appdata/secrets/
n8n_encryption_key.txt`. In DR.md 6.1 fehlt sie komplett.
`SECRETS_MAP.md:135` macht die Folgen explizit: "Bei Verlust aller
Quellen: n8n startet, aber alle gespeicherten Credentials sind unbrauchbar".
Da n8n den GMX-Mail-Workflow fuer das Gitea-`Micha/mails`-Repo betreibt,
ist das ein direkter Workflow-Ausfall.
### P2-5 (LOW) - Monitoring-/Filebrowser-Secrets fehlen in DR.md 6.1
`docs/SECRETS_MAP.md:53-55`: `influxdb3_admin_token.json`,
`monitoring_grafana_admin_password.txt`,
`monitoring_grafana_influxdb_token.txt` sowie
`filebrowser_admin_password.txt` sind nicht in DR.md 6.1. Tier-3-Apps,
Folge ist nur ein UI-Initialisierungs-Schritt nach Wiederanlauf. Keine
Critical-Konsequenz, aber Inkonsistenz.
## Phase 3 - Borg-Extract
### P3-1 (HIGH) - Borg-Client ohne `borg-ui`-Container
`docs/RESTORE_HANDBOOK.md:30-33` sagt explizit: "Borg-Zugriff laeuft ueber
den vorhandenen `borg-ui`-Container".
Im Bare-Metal-Fall ist `borg-ui` selbst kalt (Tier 3, DR.md Phase 4 Stufe 5).
Es gibt keinen dokumentierten Pfad, wie der erste Borg-Extract ohne diesen
Container laeuft. Implizite Optionen: nativer Borg auf Unraid (Plugin),
`docker run --rm borgbackup/borg`, oder Operator-Laptop. Keine davon ist
benannt.
Vorschlag: In `RESTORE_HANDBOOK.md` Abschnitt 2 einen "Bare-Metal-Vorlauf"
ergaenzen, der den initialen Borg-Extract ohne borg-ui-Container
beschreibt - z. B. `docker run --rm -v
/mnt/user/backups/restore-lab:/restore borgbackup/borg ...`.
### P3-2 (HIGH) - Borg-Passphrase-Bootstrap nicht als expliziter Schritt
`docs/DISASTER_RECOVERY.md:68`: "Host-Secret-Datei vorhanden und fuer
Borg-Zugriff verifiziert; externe Offline-Hinterlegung vom Operator am
2026-05-26 bestaetigt."
Praktisch heisst das: im Bare-Metal-Fall liest der Operator die Passphrase
aus einem analogen Medium und tippt sie in den Borg-Client. Das ist ein
**Bootstrap-Schritt**, der nicht als Schritt dokumentiert ist. Er steckt
implizit in "extern bestaetigt".
Vorschlag: Ein nummerierter Bullet in `DISASTER_RECOVERY.md` Phase 3 ("Wenn
echte Daten aus Borg benoetigt werden"): "Schritt 1: Borg-Passphrase aus
Offline-Sicherung beschaffen. Wert wird nicht in Skripte oder Tickets
kopiert; nur in den interaktiven Borg-Aufruf eingegeben."
### P3-3 (MED) - Hetzner-Maintenance-Key im Bare-Metal
`docs/EXTERNAL_DEPENDENCIES.md:17`: "Maintenance-Key liegt in Vaultwarden".
Im Bare-Metal-Bootstrap ist Vaultwarden Phase 4 Stufe 4. Damit ist der Key
fuer die initiale Phase-3-Hetzner-Verbindung nicht zugaenglich. Implizit
muss er ebenfalls offline gesichert sein (analog Borg-Passphrase).
Vorschlag: gleiche Form wie Borg-Passphrase - eine Operator-Bestaetigung
in `EXTERNAL_DEPENDENCIES.md`, dass der Hetzner-SSH-Key auch ausserhalb von
Vaultwarden offline verfuegbar ist. Sonst ist die "Vaultwarden"-Aussage
fuer Bare-Metal eine Falle.
## Phase 4 - Bootstrap-Reihenfolge
### P4-1 (HIGH) - Externe Docker-Netze in DR.md Phase 4 Stufe 1 nicht erwaehnt
`docs/SERVICES_RECOVERY.md:82-84` Stufe A schreibt explizit: "Externe
Docker-Netze existieren oder werden erzeugt (`frontend_net`, `backend_net`).
Wenn nicht vorhanden: `docker network create --driver bridge frontend_net`
bzw. `... --internal backend_net`."
`docs/DISASTER_RECOVERY.md:252-260` Phase 4 Stufe 1 nennt nur Traefik,
AdGuard, Tailscale. Kein Hinweis auf externe Netze.
`traefik/docker-compose.yml:70-76` deklariert `frontend_net`, `backend_net`,
`monitoring_net` als `external: true`. Ohne vorab erstellte Netze scheitert
der erste `docker compose up` mit "network frontend_net not found".
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 vor Stufe 1 einen Vorlauf
"Stufe 0 - Docker-Grundlage" einfuegen, der die Netzwerk-Erzeugung wie in
`SERVICES_RECOVERY.md` Stufe A explizit listet.
### P4-2 (HIGH) - Cloudflare-LE-Rate-Limit-Risiko
`docs/RESTORE_MATRIX.md:30` markiert `letsencrypt` korrekt als
Restore-relevant. `docs/DISASTER_RECOVERY.md:240` listet
`/mnt/user/appdata/traefik/letsencrypt` ebenfalls als kritischen
Borg-Restore-Pfad.
Luecke: kein Hinweis auf den Praxisfall "LE-State verloren, frischer
Acme-Run". Let's Encrypt hat ein Rate-Limit von 50 Zertifikaten/Domain/
Woche und 5 Duplicate-Zertifikate/Woche. Bei einer Multi-Sub-Domain-
Konstellation wie `*.kaleschke.info` (15+ Hostnames) ist das beim
hektischen DR-Bootstrap erreichbar.
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 Stufe 1 einen Hinweis: "Bei
verlorenem oder unklarem `acme.json` zuerst gegen
`acme-staging-v02.api.letsencrypt.org` ausstellen lassen, erst nach
gruenem Smoke auf Production-CA umschalten." Ist eine Praesentations-
Aenderung in den Compose-Args, kein neuer Code.
### P4-3 (MED) - `traefik/dynamic/*` als Pre-Check fehlt
`docs/DISASTER_RECOVERY.md:357-365` Sektion 10 beschreibt die manuelle
Sonderregel fuer `traefik/dynamic/*`. Korrekt.
`docs/DISASTER_RECOVERY.md:252-260` Phase 4 Stufe 1 verweist nicht auf
diese Sonderregel. Wer der Reihenfolge folgt und Sektion 10 nicht liest,
startet Traefik ohne Middlewares - alle 2FA-Routen brechen still.
Vorschlag: Cross-Reference in Phase 4 Stufe 1: "Vor `docker compose up
traefik` pruefen, dass `/mnt/user/appdata/traefik/dynamic/middlewares.yml`,
`tls.yml`, `dashboards.yml` vorhanden sind (Sonderregel Sektion 10)."
### P4-4 (HIGH) - Authelia "frische Postgres ohne Dump"-Pfad fehlt
`docs/DISASTER_RECOVERY.md:267-275` Phase 4 Stufe 2 startet Postgres und
Authelia. Authelia erwartet eine Rolle `authelia` mit dem Passwort aus
`authelia_postgres_password.txt`. Im Restore-Pfad mit `pg_dumpall --globals-
only` ist die Rolle abgedeckt.
Bei einem **fresh-start** (keine alten Daten, nur Container hochfahren) ist
die Rolle nicht da. Postgres-Image legt sie nicht automatisch an. Authelia
schlaegt mit "FATAL: role authelia does not exist" fehl.
Luecke: Der Initialisierungspfad fuer eine frische Postgres ohne
pg_dumpall ist in der Doku nicht beschrieben. Im echten DR mit Borg ist
das unwahrscheinlich, aber im Soft-Recovery oder Migrations-Drill schon.
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 Stufe 2 eine optionale
Anweisung: "Falls Postgres frisch ist (kein Dump-Restore), `infra/
postgresql17/init/`-Skripte oder manuelle `CREATE ROLE`/`CREATE DATABASE`-
Schritte ergaenzen."
### P4-5 (LOW) - Gitea nach Postgres ist faktisch unnoetig
`docs/DISASTER_RECOVERY.md:267-275` Phase 4 Stufe 2 ordnet Gitea hinter
Postgres ein. Gitea nutzt SQLite (`gitea.sqlite.dump`), nicht den shared
Postgres. Reihenfolge ist nicht falsch, aber irrefuehrend. Nicht kritisch.
### P4-6 (HIGH) - Komodo-Mongo Passwort-Lockout-Risiko
`ops/komodo/docker-compose.yml:18-20` zeigt: `komodo-mongo` initialisiert
sich bei leerem Datadir mit `MONGO_INITDB_ROOT_PASSWORD_FILE` aus
`/mnt/user/appdata/secrets/komodo_mongo_password.txt`.
Restore-Fall: Datadir aus Borg restauriert, Secret-Datei aus Borg
restauriert - beide aus demselben Snapshot. OK.
Riskanter Fall: Datadir aus Borg, aber Secret-Datei aus einer anderen
(neueren oder aelteren) Quelle. Mongo akzeptiert den Login nicht, Komodo
laeuft nicht. Lockout. Doku erwaehnt diesen Pin-Punkt nicht.
Vorschlag: Hinweis in `DISASTER_RECOVERY.md` Phase 4 Stufe 3: "Mongo-
Datadir und `komodo_mongo_password.txt` muessen aus demselben Snapshot
kommen. Bei Mismatch: leeren Datadir und Re-Init, dann Daten aus
`komodo-mongo.archive.gz` per `mongorestore`."
### P4-7 (MED) - Hardgecodete LAN-IP in `extra_hosts`
`ops/komodo/docker-compose.yml:50` und `:101` haben:
`"git.kaleschke.info:192.168.178.58"`.
Bare-Metal-Recovery auf anderer Hardware oder veraenderter LAN-IP fuehrt
zu stummem Fehler: Komodo-Core kann Gitea nicht ueber den Override
erreichen, faellt auf AdGuard-DNS zurueck (wenn der schon laeuft) oder
scheitert.
Vorschlag: kurzer Hinweis in `DISASTER_RECOVERY.md` Phase 4 Stufe 3: "Bei
geaenderter Host-LAN-IP `extra_hosts`-Werte in `ops/komodo/docker-compose.
yml` vor `compose up` anpassen oder ueber `.env` parametrisieren."
### P4-8 (HIGH) - Stack-ENV-Wiederherstellung praktisch manuell
`docs/DISASTER_RECOVERY.md:188-195` sagt: "Wenn `komodo-mongo.archive.gz`
frisch ist, koennen die Werte beim Komodo-Restart aus dem Dump
zurueckgespielt werden, ohne dass jemand sie sieht."
`docs/RESTORE_HANDBOOK.md:73-74` und `docs/AUDIT_2026-05-25_TODO.md:20`
machen den Daten-Mongo-Restore als "erledigt 2026-06-03" sichtbar - aber
NICHT als Teil des DR-Bootstraps. Komodo-Bootstrap im Trockenlauf benutzt
Wegwerf-Werte.
Praktisch heisst das: Im DR-Bootstrap (Phase 4 Stufe 3) startet Komodo
**ohne** den Mongo-Daten-Restore. Die `KOMODO_*` kommen aus externer
Notiz. Aber die Stack-ENVs fuer `paperless`/`immich`/`mail-archiver`/
`speedtest` (PAPERLESS_DBPASS etc.) **muessen vor Stufe 4** wieder in
Komodo eingetragen sein. Wenn der Mongo-Daten-Restore nicht direkt nach
Komodo-Start passiert, gehen diese Werte manuell in die Komodo-UI.
Vorschlag: Klarstellung in `DISASTER_RECOVERY.md` Phase 4 zwischen Stufe
3 und Stufe 4: "Optionaler Mongo-Daten-Restore aus `komodo-mongo.archive.
gz` per `ops/restore-tests/komodo-mongo-restore-test.sh`-Muster - dann
sind alle Stack-ENVs zurueck. Alternativ: Stack-ENVs manuell in Komodo-
UI eintragen, Quelle Vaultwarden (sobald Stufe 4 Vaultwarden laeuft -
Henne-Ei mit Paperless: Paperless-Start dann erst nach Vaultwarden, nicht
parallel)."
## Phase 5 - Verifikation
### P5-1 (LOW) - Smoke-Tests in DR.md weniger streng als Matrix
`docs/DISASTER_RECOVERY.md:337-345` Phase 5.3 sagt z. B. "Vaultwarden
startet und ist erreichbar". `docs/RESTORE_MATRIX.md:39` sagt: "Login-
Seite erreichbar, Tresor-Daten sichtbar". Das zweite ist faktisch der
echte Smoke-Test.
Geschmackssache, kein Bug. Empfehlung: DR.md auf die Matrix-Smokes
verweisen statt eigene Kurzversion.
### P5-2 (MED) - Kein Verifikationspunkt App-zu-DB-Verbindung
`docs/DISASTER_RECOVERY.md:337-345` prueft App-Start, nicht DB-Auth-
Erfolg. Bei falschem `PAPERLESS_DBPASS`-Stack-ENV startet Paperless
moeglicherweise mit Error-Log und ist via Traefik nicht antwortend - aber
das fehlt als Pruefpunkt.
Vorschlag: Phase 5.3 ergaenzen: "Pro App: `docker logs <app>` zeigt keine
`password authentication failed`/`FATAL: role does not exist`-Eintraege."
## Uebergreifende Findings
### X-1 (HIGH) - Nextcloud-Restore-Skript existiert, ist aber ungetestet
`ops/restore-tests/nextcloud-restore-test.sh` und
`ops/restore-tests/nextcloud-compose.test.yml` existieren im Repo.
`docs/RESTORE_MATRIX.md:147` Spalte "Letzter Restore-Test" fuer Nextcloud:
`-`, naechster Lauf `**hoechste Prio**`. `docs/AUDIT_2026-05-25_TODO.md:18`
fuehrt es als P1 "offen".
Damit ist der echte Tabletop-Gewinn: der Test ist nicht "noch zu bauen",
sondern "noch nie ausgefuehrt". Ein `bash /mnt/user/services/homelab-
infra/ops/restore-tests/nextcloud-restore-test.sh` schliesst die letzte
Tier-2-Luecke.
## Nicht-Findings
Was ich gepruft und als sauber verifiziert habe:
- Referenzierte Skripte existieren alle: `pre-backup-dumps.sh`,
`gitea-bundle-mirror.sh`, `run-restore-checks.sh`,
`komodo-bootstrap-test.sh`, `posture-check.sh`, alle Restore-Test-
Skripte fuer Tier-1 und Tier-2.
- Pfadverweise zwischen DR.md, RESTORE_MATRIX.md, SECRETS_MAP.md,
SERVICES_RECOVERY.md sind konsistent (Borg-Dumps unter `/mnt/user/
backups/borg/dumps/latest`, Secrets unter `/mnt/user/appdata/secrets`).
- Drift-Erkennung Authelia (`services/authelia-diff.sh`) ist in
`posture-check` integriert (`WORKFLOW.md:292`).
- GitHub-Mirror-Pfad und Gitea-Bundle-Mirror als Repo-Bootstrap-Quellen
sind dreifach abgesichert (lokaler Clone, GitHub, Bundle).
- Tier-1-Postgres-Restore-Drill ist 2026-06-03 erfolgreich gelaufen
(`AUDIT_2026-05-25_TODO.md:19`).
- `ops/komodo/docker-compose.yml` ist als Recovery-Anker getestet
(`SERVICES_RECOVERY.md:142-166`).
- Borg-Passphrase und Hetzner-Account-Hygiene sind Operator-bestaetigt
(`AUDIT_2026-05-25_TODO.md:46-47`).
## Vorschlag fuer Reihenfolge der Folge-Arbeit
1. **CRITICAL P1-1 zuerst** - Operator-Laptop-Voraussetzung als
DR-Pflichtposten dokumentieren. Eine Dokuzeile.
2. **HIGH P0-2 + P3-3** - klaeren, ob GitHub-Mirror lesend public ist und
wo der Hetzner-Maintenance-Key offline liegt. Zwei Dokuzeilen oder
eine echte Setup-Entscheidung.
3. **HIGH P2-1** - Operator-Bestaetigung "KOMODO_*-Notiz offline
gesichert YYYY-MM-DD" in `EXTERNAL_DEPENDENCIES.md` ergaenzen (sobald
real angelegt).
4. **HIGH P4-1 + P4-2** - Vorlauf "Stufe 0 - Docker-Grundlage" und
LE-Staging-Hinweis in DR.md Phase 4 einfuegen. Etwa 10 Zeilen Doku.
5. **HIGH X-1** - `nextcloud-restore-test.sh` einmal scharf ausfuehren.
Vermutlich ein Vormittag inklusive Report-Review.
6. **HIGH P2-2 + P4-8** - Reihenfolgen-Konsistenz Komodo/Vaultwarden in
DR.md eindeutig aufloesen.
7. Rest in der Reihenfolge der Tabelle.
Punkte 1-4 sind reine Doku-Arbeit, keine Compose-/Runtime-Aenderung.
Punkt 5 ist ein echter Restore-Lauf mit Report. Punkt 6 ist die
substanziellste Doku-Aenderung in DR.md.
## Reproduktion dieses Drills
```text
Methode: kalter Lesetest gegen
- docs/DISASTER_RECOVERY.md
- docs/RESTORE_MATRIX.md
- docs/SECRETS_MAP.md
- docs/SERVICES_RECOVERY.md
- docs/RESTORE_HANDBOOK.md
- docs/EXTERNAL_DEPENDENCIES.md
- ops/komodo/docker-compose.yml
- traefik/docker-compose.yml
Verifizierte Skript-Existenz: ops/borg-ui/scripts/*, ops/restore-tests/*,
services/posture-check/*
Kein Container gestartet, kein Skript ausgefuehrt, keine produktiven
Pfade beruehrt.
```