Erster Lauf am 2026-06-03 lief sauber durch alle Phasen (Borg-Extract,
pg_restore, Container alle gesund), schlug aber im HTTP-Smoke mit 503 fehl.
Ursache (aus dem preserved /mnt/user/backups/restore-lab/_failed/...):
- OC_Util.php:486 prueft die Permissions der data-Dir
- Skript hatte chmod -R a+rwX gesetzt (0777, letzte Stelle 7)
- Nextcloud versucht selbst chmod(0770) als www-data im Container
- Unraids shfs/FUSE lehnt chmod von Non-Root ab
- Nextcloud meldet "data directory readable by other people" -> 503
Fix: in der gepatchten config.php zusaetzlich
'check_data_directory_permissions' => false setzen. Nextcloud bietet
das in OC_Util:480 explizit als Opt-out an, fuer den isolierten Smoke
mit Wegwerf-Daten ist das vertretbar (kein Public, kein Traefik).
Produktiv bleibt der Check natuerlich an.
Patching erfolgt im bestehenden PHP-Injection-Block; idempotent (laeuft
keine Aenderung wenn beide Keys schon im config.php sind). Fallback-
sed-Pfad fuer Hosts ohne php ebenfalls erweitert.
Borg-Extract von dynamic/ und letsencrypt/, Traefik startet mit
File-Provider gegen restaurierte Config, /ping Health antwortet.
Bewusst kein docker.sock (wuerde produktive Container discovern),
kein CF-Token (keine DNS-Challenge), keine produktiven Ports.
acme.json-Existenz und -Groesse wird geprueft, TLS-Validitaet nicht.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Borg-Extract der Data-Protection-Keys + pg_restore des 645M
mailarchiver-Dumps in isoliertes Test-Postgres + Container-Boot +
HTTP-Smoke. Wegwerf-DB-Connection und Auth-Password, kein produktiver
Stack-ENV, kein Authelia-ForwardAuth im Smoke.
Machbarkeit vorab verifiziert: Dump vorhanden, App-Image gepinnt,
Data-Protection-Keys im Borg, .NET-App hat kein shfs-chmod-Problem.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Negativ-Test 2026-06-03: korrupter mealie.dump wurde nicht erkannt,
weil der Docker-Fallback-Pfad nach gescheitertem pg_restore --list
zu return 2 (unchecked) durchfiel statt return 1 (invalid).
Fix: explizites if/else statt &&-Kette, damit fehlgeschlagene
Header-Validierung return 1 liefert und als DUMP_HEADER_INVALID
in den Critical-Zaehler geht.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Produktive Mongo ist 8.0.23, Test-Composes pinnten noch 7.0.32.
Eliminiert die Cross-Version-Warnung beim mongorestore.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Kompletter Restore-Drill fuer den Shared-PostgreSQL-18-Cluster:
globals (Rollen) + 5 per-DB Custom-Format-Dumps (paperless,
mailarchiver, authelia, nextcloud, mealie).
Bekannter mailarchiver-Bootstrap-Rollenkonflikt wird toleriert.
Authelia/Nextcloud/Mealie-Dumps als optional markiert.
Tabellen-Count pro DB als fachlicher Sanity-Check.
Machbarkeit vorab verifiziert: alle Dumps auf Host vorhanden,
pg_restore im postgres:18.4-Image verfuegbar, Postgres auf shfs
bewiesen durch bestehende Tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Komodo-Mongo-Daten-Restore am 2026-06-03 erfolgreich: mongorestore
von komodo-mongo.archive.gz in Wegwerf-Mongo, 86904 Dokumente
(inkl. 32 Stack-Definitionen). Damit ist die kanonische Quelle fuer
KOMODO_*-Stack-ENV-Werte im DR-Fall als wiederherstellbar belegt.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Zweiter Lauf scheiterte mit Auth-Failure weil der Container-Name
restoretest-komodo-mongo mit dem alten Bootstrap-Test kollidierte
(stale Datadir auf shfs mit anderen Credentials).
Fix: eigenes Compose mit eigenem Container-Namen
(restoretest-komodo-mongorestore) und eigenem Project-Name, damit
keine Namenskollision mit dem bestehenden Bootstrap-Test entsteht.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Erstlauf 2026-06-03: 86904 Dokumente (inkl. 32 Stack-Dokumente)
erfolgreich restored, aber Exit 1 weil der Index-Rebuild mit
"Command createIndexes requires authentication" scheitert (Test-User
hat keine dbAdmin-Rolle).
Fix: --noIndexRestore. Fuer den Smoke-Zweck (Stack-Definitionen lesbar,
KOMODO_*-ENV-Werte rekonstruierbar) reicht das. Indexe werden bei einem
echten Komodo-Restart ohnehin neu aufgebaut.
Nebenbefund: produktive Mongo ist 8.0.23, Test-Compose pinnt 7.0.32.
Cross-Version-Warning ist fuer den Lesetest harmlos, aber der
Bootstrap-Compose-Pin sollte separat auf 8.0 nachgezogen werden.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Neuer Test: mongorestore von komodo-mongo.archive.gz in eine frische
Wegwerf-Mongo. Beweist, dass die Stack-Definitionen und damit die
KOMODO_*-Stack-ENV-Werte aus dem Dump rekonstruiert werden koennen
(kanonische Quelle laut docs/DISASTER_RECOVERY.md 6.2.1).
Machbarkeit vorab verifiziert: Dump 6.0M auf Host vorhanden,
mongorestore im mongo:7.0.32-Image verfuegbar, shfs-Write funktioniert.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Nextcloud-Restore-Test Erstlauf 2026-06-03 nach 5 Iterationen als
strukturell blockiert durch Unraid shfs/FUSE eingestuft.
Ursache: Nextcloud 33 fuehrt zur Laufzeit chmod() auf Dateien unter
/var/www/html aus (OC_Util.php#486). Auf Unraids FUSE/shfs User Shares
ist chmod nicht moeglich - weder vom Host (chown ignoriert) noch aus dem
Container (Operation not permitted), auch nicht ohne no-new-privileges.
In Produktion funktioniert Nextcloud, weil die Daten dort auf einem
Cache-Drive (XFS/BTRFS direkt) statt ueber shfs liegen.
Scaffold (Skript + Compose) bleibt im Repo als Ausgangspunkt fuer die
Loesung. Drei Optionen dokumentiert:
a) Restore-Lab auf Cache-Drive
b) Docker-Volumes statt Bind-Mounts
c) tmpfs + rsync
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Erstlauf 2026-06-03: borg_extract fuer den Nextcloud-Dump scheiterte
still (Pfad local/borg-dumps/latest/nextcloud.dump existiert im
Archiv moeglicherweise unter einem anderen Prefix). Der Dump liegt
taeglich frisch auf dem Host unter /mnt/user/backups/borg/dumps/latest/
und wird von dort in Borg gesichert - der Smoke-Wert ist identisch.
HTML (App-Code + config) kommt weiterhin aus dem Borg-Archiv.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Zweiter Erstlauf 2026-06-03 scheiterte weiterhin mit 503, obwohl
config.php korrekt gepatcht war.
Ursache: Unraid's FUSE/shfs-Dateisystem auf User-Shares ignoriert
chown -R 33:33 still — Dateien bleiben bei sshd:sshd. Der
Nextcloud-Entrypoint versucht intern chmod/chown auf /var/www/html und
/var/www/html/data, was mit no-new-privileges:true blockiert wird.
Fix:
- no-new-privileges vom restoretest-nextcloud Container entfernt,
damit der Entrypoint Rechte im Container selbst setzen kann
(Test-Postgres und Test-Redis behalten no-new-privileges)
- Host-seitiger chown durch chmod a+rwX ersetzt (funktioniert auf shfs)
- Vertretbar im isolierten Smoke-Kontext (127.0.0.1, Wegwerf-Daten,
kein Traefik)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Erstlauf 2026-06-03 scheiterte mit dauerhaft 503. config.php-Patching
(Redis-Host + trusted_domains) war korrekt, aber Nextcloud konnte die
restaurierten Dateien nicht lesen/schreiben: "chmod(): Operation not
permitted at OC_Util.php#486".
Ursache: Borg-Extract ueber den borg-ui Container legt Dateien mit dem
borg-ui-User (sshd o.ae.) an. Nextcloud im Container laeuft als
www-data (UID 33). Mit no-new-privileges:true scheitert jeder chmod/
chown-Versuch im Container.
Fix: chown -R 33:33 auf html/ und data/ nach dem Extract, bevor der
Nextcloud-Container startet.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Erstlauf 2026-06-03 scheiterte mit 503: Redis-Host war noch auf dem
produktiven 'nextcloud-redis' statt 'restoretest-nextcloud-redis', und
trusted_domains enthielt kein 127.0.0.1 (Nextcloud blockt mit
"Access through untrusted domain").
Ursache: das sed-Pattern fuer Redis versuchte den ganzen Array-Block
einzeilig zu ersetzen, traf aber das PHP-Mehrzeilenformat nicht. Und
das trusted_domains-sed fand das Schliessmuster nicht zuverlaessig.
Fix:
- Redis-Host separat per sed patchen (nur den 'host'-Wert im Block)
- trusted_domains per PHP-CLI rewrite (robuster als sed auf PHP-Arrays)
- Fallback auf sed fuer Hosts ohne php
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Nextcloud-Restore-Test nach dem Muster der anderen Restore-Smokes:
- Borg-Extract von html (App-Code + config.php) und nextcloud.dump
- pg_restore in isoliertes Test-Postgres (mit Retry-Schleife)
- config.php wird im Restore-Lab auf Test-DB-Credentials gepatcht
(produktive Secrets werden nicht gemountet)
- Nextcloud startet gegen restaurierte Daten + Test-Redis
- Smoke prueft HTTP /status.php und occ status (maintenance mode)
- Produktive Nutzdaten unter /mnt/user/documents/nextcloud-data
werden bewusst NICHT gemountet (zu gross fuer regelmaessigen Smoke)
Erster Lauf steht aus und braucht Operator-Freigabe auf dem Host.
Dispatcher und ntfy-Wrapper um Nextcloud erweitert.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Erstlauf 2026-06-03 hat einen by-design-Konflikt offengelegt: pg_restore des
produktiven postgresql17-authelia.dump in eine Test-Instanz mit Wegwerf
AUTHELIA_STORAGE_ENCRYPTION_KEY scheitert im Authelia-Startup-Check mit
"the configured encryption key does not appear to be valid for this database".
Productive Storage-Werte werden mit dem produktiven Key verschluesselt; ein
Wegwerf-Key kann sie nicht entschluesseln. Smoke ist deshalb explizit auf
Config-Restore + Boot reduziert, nicht Daten-Decrypt.
Zwei Nebenbefunde aus demselben Lauf:
- AUTHELIA__SERVER__ADDRESS (Doppel-Underscore) wurde von Authelia 4.39
abgelehnt ("configuration environment variable not expected"). ENV
entfernt; server.address kommt eh aus der generierten configuration.yml.
- ntp-Startup-Check schlug fehl ("Could not determine the clock offset
... lookup time.cloudflare.com on 127.0.0.1:53: server misbehaving"),
weil das isolierte Test-Compose-Netz keinen DNS-Resolver fuer NTP hat.
Neuer Test-Config-Block setzt ntp.disable_startup_check: true.
Doku nachgezogen (Plan + Runbook): Encryption-Key-Konflikt ist explizit
als "nicht Teil dieses Smokes" dokumentiert; Fehler-Matrix hat Eintraege
fuer Doppel-Underscore-ENV und NTP-Lookup.
Frische des produktiven authelia-Dumps wird unveraendert ueber
check-restore-freshness.sh ueberwacht; Daten-Decrypt-Drill ist eine eigene
DR-Aufgabe mit kontrollierter Schluessel-Verwendung.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Authelia 4.39 verlangt: ohne access_control.rules muss default_policy
'two_factor' oder 'one_factor' sein. 'bypass' war nur historisch zulaessig,
mit 4.39 schlaegt config validate fehl mit "'default_policy' option
'bypass' is invalid: when no rules are specified it must be 'two_factor'
or 'one_factor'". /api/health ist public und laeuft nicht durch
access_control - die Smoke-Semantik bleibt unveraendert.
Beobachtet im Erstlauf 2026-06-03 nach Refactor auf Minimal-Testkonfig
(Commits 541c7be..440000c). Mit diesem Fix sollte 'authelia config
validate' durchlaufen; HTTP /api/health-Smoke ist der Folgeschritt.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ops/policy-checks/mem-limits-baseline.md captures the deliberate
"not today" decision for memory limits plus the plan for when it
becomes relevant:
- Phase 1: 7 days of hourly docker stats snapshots
- Phase 2: derive Tier-1 peak per container
- Phase 3: set limits at peak * 1.5 with documented floors
(Postgres 1G, Mongo 1G, Redis 256M, etc.)
- Phase 4: roll out smallest-risk containers first, observe 24h
between stages
- Phase 5: Tier-2 only after a concrete trigger event
Next trigger: family invitation out + 4 weeks stable use, or
first real OOM event in docker-critical-events.sh, or a sudden
Immich/Nextcloud load spike where host swap becomes visible.
Today's policy check is clean (0 Critical, 1 documented Warning
on influxdb3-core user 0, 13 documented Info findings on host
ports / privileged exceptions / latest+digest tags).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
Drei Issues beim Erstlauf gefunden und gefixt:
1. EAI_AGAIN: Renovate-Container konnte git.kaleschke.info nicht
aufloesen. Analog zu Komodos extra_hosts mappen wir den Hostname
per --add-host auf 192.168.178.58 (LAN-IP des Unraid-Hosts).
Zusaetzlich --dns 1.1.1.1/8.8.8.8 fuer externe Image-Registries.
2. Token-Leak in ps und docker inspect: -e RENOVATE_TOKEN=... macht
den Wert in Process-Listing sichtbar. Stattdessen --env-file mit
einem 0600 tempfile unter $RENOVATE_STATE_DIR/.env, das nach dem
Lauf via shred bzw. rm geloescht wird.
3. Doppelter rc=$? Block plus return innerhalb einer {}-Subshell
waren Tot-Code; aufgeraeumt.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
renovate.json: gitea platform, autodiscover Micha/*, group rules
(major separate, minor+patch+digest grouped, stateful tier-1
individual, komodo-major disabled), pin range strategy, no
automerge, dependency dashboard enabled.
ops/renovate/run-renovate.sh: one-shot docker run wrapper that
reads the Gitea PAT from /mnt/user/appdata/secrets/renovate_token.txt,
runs renovate/renovate:41, logs into /mnt/user/services/renovate/logs/.
docs/RENOVATE.md: 5-step operator setup (Gitea service account,
PAT, token file, first run, six-hourly user script). Explicit
no-automerge stance with notfall-stop checklist.
Cross-doc sweep: SECRETS_MAP entry for renovate_token.txt,
REPO_MAP entry for RENOVATE.md, AUDIT_2026-05-25_TODO new
Sprint 8 with F-15, F-07, F-09 rest, F-12 status, MIGRATION_LOG
captures the four-block sprint in one entry.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>