Files
homelab-infra/ops/h-drive-nearline/README.md
T
Micha 1a4593110a nearline: S4U-Root-Cause dokumentiert + Exitcode-Leak gefixt
Diagnose 2026-06-21: Der Scheduled Task "KalliLab H Drive Nearline Pull"
lief als LogonType S4U (ohne gespeichertes Passwort) und hatte damit keine
Netzwerk-Anmeldeinformationen fuer den SMB-Share \192.168.178.58\backups.
Jeder geplante 05:30-Lauf brach still mit Exit 1 ab, ohne Report; der
Nearline-Spiegel war 2026-06-19 bis 2026-06-21 veraltet. Manuell nachgezogen,
Spiegel wieder frisch.

pull-critical-backups.ps1: explizites `exit 0` auf dem Erfolgspfad, damit der
letzte robocopy-Exitcode (1 = "Dateien kopiert") nicht als Prozess-Exit leakt
und der Scheduled Task ein wahrheitsgemaesses Ergebnis meldet.

README: Pflicht-Hinweis, dass der Task mit gespeichertem Passwort (nicht S4U)
laufen muss. MASTER_TODO: Root-Cause + verbleibender Operator-Schritt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:02:58 +02:00

6.0 KiB

H:/ Nearline-Backup — Struktur und Betrieb

Stand: 2026-06-21

Rolle der H:/

Die externe HDD (asmedia ASM235, 7.4 TB, Laufwerk H:) dient ausschließlich als Nearline-Backup-Spiegel für kritische Dumps und Git-Bundles.

Sie ist kein Primär-Backup (das ist Hetzner/Borg) und kein dauerhaftes Archiv.

Sollzustand

H:\
└── kallilab-nearline-backups\
    ├── borg-dumps\latest\      ← aktuelle DB-Dumps (per Script)
    ├── git-bundles\gitea\      ← Gitea-Repo-Bundles (per Script)
    ├── _dr-kit\                ← SSH-Keys, Offline-Secrets (manuell)
    ├── _logs\                  ← Robocopy-Logs je Lauf
    └── _reports\               ← Markdown-Reports je Lauf

Nichts weiteres gehört dauerhaft auf die H:/. Temporäre Recovery- oder Backup-Ordner aus Notfallsituationen sind nach Abschluss zu löschen.

Automatischer Pull

pull-critical-backups.ps1 zieht per Robocopy vom Unraid-SMB-Share:

  • \\192.168.178.58\backups\borg\dumps\latestborg-dumps\latest\
  • \\192.168.178.58\backups\git-bundles\giteagit-bundles\gitea\

Der Windows Scheduled Task KalliLab H Drive Nearline Pull laeuft seit 2026-05-28 taeglich 05:30. Das Script kopiert bewusst nicht mit /MIR und loescht nichts auf H:/; alte Artefakte werden nur nach manueller Sichtpruefung entfernt.

Wichtig — Task-LogonType: Der Task muss mit "Ausfuehren, auch wenn der Benutzer nicht angemeldet ist" und gespeichertem Passwort laufen (LogonType Password). Mit S4U (ohne gespeichertes Passwort) hat der Lauf keine Netzwerk-Anmeldeinformationen und erreicht den authentifizierten SMB-Share \\192.168.178.58\backups nicht -> jeder geplante Lauf bricht still mit Exitcode 1 ab, ohne Report. Genau das passierte 2026-06-19 bis 2026-06-21 (Spiegel still veraltet), bis am 2026-06-21 manuell nachgezogen wurde. Manuelle Laeufe in einer interaktiven Sitzung funktionieren, weil die Sitzung die SMB-Creds hat. Das ist auch der Grund fuer den externen Dead-Man's-Switch unten.

Aufruf zum Testen:

powershell.exe -NoProfile -ExecutionPolicy Bypass -File G:\Gitea_Clone\homelab-infra\ops\h-drive-nearline\pull-critical-backups.ps1 -WhatIf

Das Script schließt bewusst aus:

  • unraid-flash-config.tar.gz (0600 root:root, nicht per SMB zugänglich → Restore aus Hetzner-Borg)
  • Migration-/Cutover-Verzeichnisse (immich-vectorchord-*, pg18-major-*, redis8-* etc.)

Externer Dead-Man's-Switch

Der Pull lief ~2026-06-04 bis 2026-06-18 still gestoppt, ohne dass etwas Alarm schlug (Scheduled Task fehlte; Prometheus auf Unraid sieht den baerchen-Pull nicht). Gegenmittel: ein externer Heartbeat. pull-critical-backups.ps1 pingt am Lauf-Anfang /start, am Ende den Erfolg und im Fehlerfall /fail. Bleibt der Erfolgs-Ping aus, alarmiert der externe Dienst von aussen.

Die Integration ist endpoint-agnostisch: jede Healthchecks-kompatible URL funktioniert (Healthchecks.io-Cloud oder self-hosted). Ist keine URL gesetzt, ist der Switch ein No-Op und der Pull laeuft unveraendert weiter.

URL-Quelle (in dieser Reihenfolge):

  1. Parameter -HealthchecksUrl
  2. ENV HEALTHCHECKS_NEARLINE_URL
  3. Datei %USERPROFILE%\.kallilab\healthchecks-nearline-url.txt

Die Ping-URL ist eine Capability-URL -> wie ein Secret behandeln, nie ins Repo (siehe docs/SECRETS_MAP.md).

Operator-Setup (einmalig)

  1. Check anlegen (Healthchecks.io oder self-hosted): Period = 1 Tag, Grace z. B. 2-3 h passend zum taeglichen 05:30-Task. Ping-URL kopieren.
  2. Auf baerchen die URL hinterlegen, z. B. als Datei:
    New-Item -ItemType Directory -Force -Path "$HOME\.kallilab" | Out-Null
    Set-Content -LiteralPath "$HOME\.kallilab\healthchecks-nearline-url.txt" -Value "https://hc-ping.com/<uuid>" -NoNewline
    
    (alternativ als persistente User-Umgebungsvariable HEALTHCHECKS_NEARLINE_URL.)
  3. Testlauf: pull-critical-backups.ps1 ausfuehren; im Healthchecks-Dashboard muss ein "success"-Ping ankommen.

Borg-Pre-Hook-Pendant

Den gleichen Switch gibt es host-seitig in ops/borg-ui/scripts/pre-borg.sh. URL dort via ENV HEALTHCHECKS_BORG_URL oder Datei /mnt/user/appdata/secrets/healthchecks_borg_url (chmod 600), bewusst als eigener Check (getrennter Heartbeat fuer die Unraid-Backup-Vorpruefung).

_dr-kit

Enthält offline hinterlegte Schlüssel und Secrets für den DR-Fall:

  • dr-hetzner / dr-hetzner.pub — SSH-Key für Hetzner Storage Box
  • dr-readonly / dr-readonly.pub — Read-only Deploy-Key
  • KOmodo Secrets.txt — Komodo Stack ENV-Offline-Dokumentation

Diese Dateien sind manuell zu pflegen und nicht vom Pull-Script verwaltet.

Archiv-Ordner

Temporäre Notfall-Artefakte verbleiben als _archiv-*-Ordner bis zur bewussten Löschentscheidung:

Ordner Inhalt Anlassdatum
kallilab-recovery\_archiv-nvme-crash-image-2026-05-14\ nvme0n1 Disk-Image (1863 GB) + Crash-Runbooks aus dem Mai-2026-Ausfall 2026-05-14

Aufräum-Historie

Datum Aktion
2026-06-10 OneDrive - Stroetmann Group\ gelöscht (leer)
2026-06-10 SSH-Keys + Secrets aus nearline-Root in _dr-kit\ verschoben
2026-06-10 Migration-Artefakt-Verzeichnisse in borg-dumps\latest\ gelöscht (immich-vectorchord-, pg18-major-, redis8-, nextcloud-redis-pre-redis8-, shared-redis-pre-redis8-*)
2026-06-10 Pre-major-prod-Dumps gelöscht (PG17→PG18-Migration abgeschlossen)
2026-06-10 kallilab-recovery\2026-05-15\ gelöscht (DNS-Restore-Reste)
2026-06-10 kallilab-recovery\2026-05-14\_archiv-nvme-crash-image-2026-05-14\ umbenannt
2026-06-10 kallilab-recovery\disk1-phase2-2026-05-23\ gelöscht (1677 GB Media-Share-Kopie; Unraid-Share verifiziert vollständig)

Offene Punkte

  • Windows-Neuaufsetzen-Backup\ (48 GB): nach vollständiger Rückspielung auf D:\ löschen
  • _archiv-nvme-crash-image-2026-05-14\ (1863 GB): löschen sobald sicher, dass nichts mehr aus dem alten System benötigt wird
  • Log-Rotation für _logs\ und _reports\: manuell oder per Script, Empfehlung 30 Tage