Files
homelab-infra/docs/SERVICES_RECOVERY.md
T
Micha 67ec40b762 Docs sweep: reflect Komodo bootstrap first run + clean stale "still open" notes
Six files had outdated status notes that the F-09 first run on
2026-05-30 made wrong:

- ops/restore-tests/komodo-bootstrap-runbook.md: "Erster echter Lauf
  steht noch aus" -> first run confirmed
- ops/restore-tests/komodo-bootstrap-plan.md: "Noch offen vor dem
  ersten echten Lauf" section -> "Bestaetigte Laeufe" table with
  the --what-if and --keep-data runs
- ops/restore-tests/immich-runbook.md: status note still said
  "Erster echter Lauf steht noch aus" although the Immich first run
  was 2026-05-27; correcting in the same sweep
- docs/AUDIT_2026-05-25_TODO.md: Sprint 2 entry on Komodo bootstrap
  path no longer carries the "Trockenlauf-Skript bleibt als offene
  Folgeaufgabe" tail
- docs/SERVICES_RECOVERY.md: replaced the "Trockenlauf-Idee (Doku-only,
  nicht ausgefuehrt)" section with the confirmed repo-script flow and
  marked the two "Naechste Aufgaben" rows about the dry-run as done
- docs/RESTORE_DRILL_ROUTINE.md: Q2 2026 DR-Sanity-Check entry now
  splits Komodo-Bootstrap-Pfad (done) from the two still-open items
  (Gitea bundles, secrets inventory)

No behavior change, only documentation consistency.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 11:18:37 +02:00

10 KiB

Services Recovery - KalliLab CORE

Status: Initiale Recovery-Baseline 2026-05-26, aus dem Audit 2026-05-25 abgeleitet. Verwandte Docs: docs/DISASTER_RECOVERY.md, docs/RESTORE_MATRIX.md, docs/STORAGE_LAYOUT.md, docs/SECRETS_MAP.md

Zweck

Der Share /mnt/user/services/ ist recovery-kritisch, weil dort GitOps- und Host-Automation-Pfade liegen. Dieses Dokument beschreibt, welche Services-Pfade gesichert werden muessen und wie ein Kaltstart ohne laufendes Komodo gedacht ist.

Kritische Pfade

Pfad Zweck Kritikalitaet Backup-Anforderung
/mnt/user/services/homelab-infra Host-Repo-Clone fuer Automation/Posture hoch Borg + GitHub/Gitea Mirror
/mnt/user/services/stacks Komodo Stack Workspaces hoch Borg, vor strukturellen Aenderungen extra sichern
/mnt/user/services/gitea/git/repositories Gitea Repository-Inhalte kritisch Borg + separater Mirror <= 6 h
/mnt/user/services/posture-check Hostseitig ausgefuehrte Checks hoch Borg + Repo-Abgleich
/mnt/user/appdata/secrets Runtime Secrets kritisch Borg + ausgewählte analoge/off-system Kopien

Gitea Repository Mirror

Ziel: Verlustfenster fuer /mnt/user/services/gitea/git/repositories/ auf maximal 6 Stunden begrenzen.

Optionen:

Option Bewertung
git bundle je Repository auf zweites Medium Sehr gut fuer Git-Recovery, transparent, gut pruefbar
rsync auf externe Platte oder zweiten Host Einfach, aber Ziel muss regelmaessig erreichbar und geprueft sein
Separates Borg-Repo mit kurzem Schedule Konsistent zum bestehenden Backup, aber wieder Borg-/Passphrase-abhaengig

Empfohlener Start:

  1. ops/borg-ui/scripts/gitea-bundle-mirror.sh auf dem Host ausfuehren.
  2. Ziel /mnt/user/backups/git-bundles/gitea in Borg/off-site Scope aufnehmen.
  3. Job alle 6 Stunden oder mindestens vor Borg ausfuehren.
  4. Stichprobe: ein Bundle in Wegwerfpfad klonen.

Erstlauf 2026-05-26: 4 Gitea-Bundles erzeugt, Checksums OK, homelab-infra.bundle in Restore-Lab geklont und git fsck sauber. Offen bleibt die dauerhafte Host-Zeitplanung.

Erfolgskriterium:

git clone /path/to/repo.bundle /tmp/repo-restore-test
git -C /tmp/repo-restore-test fsck

Komodo Bootstrap

Problemstellung

Komodo verwaltet alle Stacks per GitOps, ist aber selbst Teil des Recovery-Pfads. Ein kalter Host darf nicht voraussetzen, dass Komodo schon laeuft. Das ist das klassische Henne-Ei-Problem: Komodo darf sich nicht selbst aus dem Repo holen muessen, bevor es laufen kann.

Recovery-Anker (verbindlich)

Anker: ops/komodo/docker-compose.yml aus dem Repo.

Dieses Compose-File ist die einzige Quelle, aus der Komodo nach einem Kaltstart hochgefahren wird. Es wird nicht ueber Komodos eigenen Auto-Deploy-Pfad konsumiert.

Was der Anker bewusst NICHT ist:

  • nicht der Komodo-Self-Stack (Komodo darf sich nicht selbst deployen).
  • nicht der laufende Komodo-Workspace unter /mnt/user/services/stacks/komodo/compose.yaml (kann driften, siehe HOMELAB_ARCHITECTURE_MASTER_V2.md Sektion 13, Drift-Recovery 2026-05-04).
  • nicht ein Gitea-Webhook (komodo-Stack hat bewusst webhook_enabled: false).

Quelle der Compose-Datei:

  1. Vorzug: lokaler Repo-Clone auf dem Operator-Windows-PC (G:\Gitea_Clone\homelab-infra\).
  2. Fallback: GitHub-Mirror michaelkaleschke-spec/homelab-infra (siehe docs/EXTERNAL_DEPENDENCIES.md).
  3. Letzter Fallback: Gitea-Bundles unter /mnt/user/backups/git-bundles/gitea/homelab-infra.bundle (siehe Mirror-Abschnitt oben).

Wenn alle drei Quellen down sind, ist Recovery blockiert und das Problem ist nicht Komodo, sondern Repo-Verlust.

Kaltstart-Schritte

Der Wiederanlauf-Pfad ist linear; jeder Schritt hat ein eindeutiges Erfolgskriterium, bevor der naechste laeuft.

Stufe A - Host und Docker-Grundlage

  1. Unraid bootet; Array ist online; Shares /mnt/user/appdata, /mnt/user/services, /mnt/user/backups sichtbar.
  2. Docker-Daemon laeuft (docker info antwortet).
  3. 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.

Erfolgskriterium: docker network ls zeigt frontend_net und backend_net.

Stufe B - Repo-Quelle bereitstellen

  1. Repo-Clone aus dem bevorzugten Pfad bereithalten:
    • lokaler Operator-Clone, oder
    • frischer Clone aus GitHub-Mirror, oder
    • Bundle-Restore aus /mnt/user/backups/git-bundles/gitea/homelab-infra.bundle (git clone homelab-infra.bundle homelab-infra).
  2. Repo-Stand verifizieren: git -C <pfad> log --oneline -1 zeigt einen plausibel aktuellen Commit.

Erfolgskriterium: ops/komodo/docker-compose.yml ist auf dem Host lesbar.

Stufe C - Komodo-Secrets bereitstellen

Komodo braucht beim Start mehrere Secrets, die nicht aus dem Repo kommen. Restore-Reihenfolge gemaess docs/SECRETS_MAP.md:

  1. Host-Secrets unter /mnt/user/appdata/secrets/ wiederherstellen (aus Borg oder analog gesicherter Quelle).
  2. Datei /mnt/user/appdata/secrets/komodo_mongo_password.txt ist Pflicht (Mongo-Initialisierung).
  3. Stack-ENV-Werte KOMODO_SECRET_KEY, KOMODO_WEBHOOK_SECRET, KOMODO_JWT_SECRET, KOMODO_MONGO_PASSWORD, KOMODO_PERIPHERY_PASSKEY muessen als Host-.env neben dem Compose vorliegen. Quelle in dieser Reihenfolge: Vaultwarden (sobald restauriert), externe Operator-Notiz, oder Komodo-Mongo-Dump (nur wenn Mongo separat bereits gestartet und die stack-Collection lesbar ist).

Erfolgskriterium: Compose-Validierung laeuft ohne fehlende Variablen.

docker compose -f ops/komodo/docker-compose.yml config >/dev/null

Stufe D - Komodo starten

  1. Compose hochfahren:
docker compose -f ops/komodo/docker-compose.yml up -d
  1. Reihenfolge intern: komodo-mongo zuerst healthy, dann komodo-core, dann komodo-periphery.
  2. Status pruefen:
docker ps --filter "name=komodo"
docker logs --tail 50 komodo-core
docker logs --tail 50 komodo-periphery

Erfolgskriterium: alle drei Container laufen; Komodo-Core meldet Bind auf Port 9120; Periphery meldet erfolgreiche Verbindung zu Core.

Stufe E - Web-UI und GitOps validieren

  1. https://komodo.kaleschke.info ist erreichbar (Authelia-Bypass dokumentiert, native Komodo-Auth aktiv).
  2. Komodo zeigt im Web-UI die bekannten Stacks aus Gitea (sobald Gitea ebenfalls laeuft; siehe docs/DISASTER_RECOVERY.md Phase 4 Stufe 2 vor Stufe 3).
  3. Gitea-Webhooks gegen Komodo werden separat in der Phase-4-Reihenfolge geprueft, nicht als Teil des Komodo-Bootstraps.

Erfolgskriterium: Komodo-UI laedt, Periphery Online, mindestens ein Stack aus Gitea sichtbar.

Stufe F - Stacks in Tier-Reihenfolge aufnehmen

Erst nach erfolgreichem Komodo-Bootstrap werden produktive Stacks ueber den dokumentierten Stufenpfad in docs/DISASTER_RECOVERY.md Phase 4 hochgefahren (Traefik, AdGuard, Tailscale, dann PostgreSQL, Authelia, Redis, Gitea, dann Apps).

Trockenlauf (als Repo-Skript, bestaetigt)

Trockenlauf gegen Wegwerf-Pfade ist seit 2026-05-29 als Repo-Skript abgelegt: ops/restore-tests/komodo-bootstrap-{compose.test.yml,test.sh,plan.md,runbook.md}. Aufruf:

bash /mnt/user/services/homelab-infra/ops/restore-tests/komodo-bootstrap-test.sh --what-if   # nur Plan
bash /mnt/user/services/homelab-infra/ops/restore-tests/komodo-bootstrap-test.sh --keep-data # echter Lauf

Erstlauf 2026-05-30 erfolgreich: SUCCESS, alle 5 Checks gruen (compose config valid, Mongo healthy, Mongo authenticated ping ok, Komodo Core HTTP 200, Test-Periphery running). Report unter /mnt/user/backups/restore-reports/komodo-bootstrap-2026-05-30.md. Produktive Komodo-Container, Mongo-Datadir und Secrets wurden nicht beruehrt.

Test-Isolation:

Bereich Wegwerf-Wert
Compose-Project restoretest-komodo (isoliert von Produktions-Project komodo)
Test-Mongo-Datadir /mnt/user/backups/restore-lab/komodo/mongo
Test-Port 127.0.0.1:19120 (kein LAN, kein Traefik)
Test-Periphery ohne docker.sock-Mount, ohne /mnt/user/services-Mount
KOMODO_*-Secrets Wegwerf-Werte im Test-Compose, niemals produktive Werte

Damit ist ops/komodo/docker-compose.yml als Recovery-Anker fuer Stufen A-F belegt tauglich, nicht nur angenommen tauglich.

Validierungs-Kommandos (Snapshot)

# Compose syntaktisch ok?
docker compose -f ops/komodo/docker-compose.yml config >/dev/null

# Komodo-Container vorhanden und laufend?
docker ps --filter "name=komodo" --format "table {{.Names}}\t{{.Status}}"

# Mongo Health?
docker exec komodo-mongo mongosh --quiet --eval 'db.adminCommand({ping:1}).ok'

# Core API up?
docker exec komodo-core sh -lc 'wget -q -O- http://127.0.0.1:9120/api/health || true'

# Periphery sichtbar?
docker logs --tail 50 komodo-periphery 2>&1 | grep -i "connected\|periphery"

Secrets Recovery Reihenfolge

Authoritativ ist docs/SECRETS_MAP.md. Fuer den Kaltstart ist diese Reihenfolge praktisch:

  1. Borg-Passphrase analog/off-system beschaffen.
  2. Borg-Repo-Zugang/SSH-Key wiederherstellen.
  3. /mnt/user/appdata/secrets/ aus Borg wiederherstellen.
  4. Komodo Stack ENV / Recovery ENV wiederherstellen.
  5. Gitea Secrets und SSH-Material wiederherstellen.
  6. Traefik/Cloudflare Secret wiederherstellen.
  7. App-spezifische Secrets nach Tier-Reihenfolge wiederherstellen.

Break-glass Regeln

  • Keine Secret-Werte in Git oder Tickets kopieren.
  • Restore-Tests laufen in Wegwerfpfaden, nie direkt gegen produktive Pfade.
  • Wenn Gitea und Komodo beide down sind, gewinnt der externe GitHub-Mirror als Repo-Quelle.
  • Wenn Borg ohne Passphrase nicht entschluesselbar ist, ist Recovery blockiert. Die Offline-Sicherung wurde am 2026-05-26 vom Operator bestaetigt; bei Reviews nur pruefen, dass sie weiterhin auffindbar und lesbar ist.

Naechste Aufgaben

Status Aufgabe
erledigt (Skript + Host-Test) Gitea-Bundle- oder Mirror-Mechanik final entscheiden
erledigt Komodo-Bootstrap-Quelle finalisieren
erledigt (Doku) Komodo-Kaltstart in linearen Stufen A-F dokumentieren
erledigt 2026-05-29 Komodo-Trockenlauf-Skript in ops/restore-tests/ analog zu Immich vorbereiten
erledigt 2026-05-30 Restore-Kommandos nach erstem Trockenlauf mit echten Pfaden ergaenzen
erledigt Services-Recovery in docs/DISASTER_RECOVERY.md verlinken