# 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: ```bash 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 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. ```bash docker compose -f ops/komodo/docker-compose.yml config >/dev/null ``` **Stufe D - Komodo starten** 1. Compose hochfahren: ```bash docker compose -f ops/komodo/docker-compose.yml up -d ``` 2. Reihenfolge intern: `komodo-mongo` zuerst healthy, dann `komodo-core`, dann `komodo-periphery`. 3. Status pruefen: ```bash 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`, `ops/restore-tests/komodo-bootstrap-test.sh`, `ops/restore-tests/komodo-bootstrap-plan.md` und `ops/restore-tests/komodo-bootstrap-runbook.md`. Aufruf: ```bash 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) ```bash # 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 |