diff --git a/docs/AI_CONTEXT.md b/docs/AI_CONTEXT.md index 8ced10b..c64f478 100644 --- a/docs/AI_CONTEXT.md +++ b/docs/AI_CONTEXT.md @@ -1,6 +1,6 @@ # AI Context -Stand: 2026-05-31 +Stand: 2026-06-01 Kurzer Kontext fuer KI-Agenten. Nicht als Ersatz fuer die echten Runbooks lesen. @@ -47,8 +47,12 @@ Authoritativ: `docs/AUDIT_2026-05-25_TODO.md`. Kurzfassung: -- naechsten Borg-Lauf nach den Dumps vom 2026-05-31 21:42 bestaetigen - Alt-Volumes fruehestens ab 2026-06-02 freigeben - Hetzner-Account-Hygiene und Borg `append-only` pruefen - FRITZ!Box-Servicefenster fuer Update, Config-Backup und IPv6-Exposure planen - Auth-/OIDC-/CrowdSec-/Hermes-Themen bewusst geparkt + +Letzte Bestaetigung: + +- Borg-Nachlauf 2026-06-01 erfolgreich: Archiv `Taegliche-Sicherung-2026-06-01T04:30:26.913`, Freshness Critical 0 / Warnings 0. +- H:/ Nearline-Pull 2026-06-01 repariert: Borg-Dumps werden kuratiert kopiert, Gitea-Bundles aktuell. diff --git a/docs/AUDIT_2026-05-25_TODO.md b/docs/AUDIT_2026-05-25_TODO.md index da49b80..654ab42 100644 --- a/docs/AUDIT_2026-05-25_TODO.md +++ b/docs/AUDIT_2026-05-25_TODO.md @@ -7,7 +7,6 @@ Audit-Snapshots wurden aus der Arbeitskopie entfernt; Detailhistorie liegt in Gi | Prioritaet | Punkt | Naechster Schritt | |---|---|---| -| P0 | Borg-Lauf nach den Dumps vom 2026-05-31 21:42 bestaetigen | Nach dem naechsten regulaeren Lauf pruefen, ob die frischen Dumps im Hetzner-Borg-Archiv liegen | | P0 | Alt-Volumes nach Burn-in freigeben | Nicht vor 2026-06-02 loeschen; vorher aktiven Pfad und letzten Borg-Lauf pruefen | | P1 | Hetzner-Account-Hygiene | Starkes einzigartiges Passwort, Backup-Zahlungsweg und Login-Benachrichtigungen extern bestaetigen | | P1 | Borg `--append-only` fuer Hetzner pruefen | Rollback-faehigen Test fuer `borg serve --append-only` in Hetzner `authorized_keys` planen | @@ -29,6 +28,8 @@ Audit-Snapshots wurden aus der Arbeitskopie entfernt; Detailhistorie liegt in Gi ## Zuletzt geschlossen +- Borg-Nachlauf nach dem 2026-05-31-Sprint ist belegt: Archiv `Taegliche-Sicherung-2026-06-01T04:30:26.913`, 101669 Dateien, `rc=0`; Freshness-Check am 2026-06-01: Critical 0, Warnings 0. +- H:/ Nearline-Pull am 2026-06-01 repariert und manuell validiert: kuratierte Borg-Dumps Exit 0, Gitea-Bundles Exit 1 (Robocopy-Erfolg mit Kopien), Report `nearline-pull-2026-06-01-082553.md`. - Immich-, Paperless-, Gitea- und Vaultwarden-Restore-Pfade sind belegt. - H:/ Nearline-Pull laeuft seit 2026-05-28 als Windows Scheduled Task. - FRITZ!Box-Portfreigaben sind bereinigt: WAN-seitig bleibt `443/tcp`. diff --git a/docs/CAPACITY_AND_LIFECYCLE.md b/docs/CAPACITY_AND_LIFECYCLE.md index b7d3d47..31c7512 100644 --- a/docs/CAPACITY_AND_LIFECYCLE.md +++ b/docs/CAPACITY_AND_LIFECYCLE.md @@ -95,3 +95,4 @@ Der konkrete Pull-Pfad ist in `docs/H_DRIVE_NEARLINE_PULL.md` und `ops/h-drive-n | 2026-05-26 | H:/ Kapazitaet erfasst: 8.0T NTFS, 3.91T belegt, 4.10T frei, `Healthy` | genug Reserve fuer Nearline-Pull der kritischen Restore-Artefakte | | 2026-05-27 | H:/ Pull-Workflow vorbereitet | SMB-Quelle `\\192.168.178.58\backups` erreichbar; PowerShell-Skript und Runbook erstellt | | 2026-05-28 | H:/ Pull-Workflow produktiv | Windows Scheduled Task `KalliLab H Drive Nearline Pull` taeglich 05:30 aktiv | +| 2026-06-01 | H:/ Pull nach Redis-/Major-Cutover-Artefakten gehaertet | Borg-Dumps-Job kopiert nur kuratierte Pflichtdateien; manueller Kontrolllauf erzeugte Report `nearline-pull-2026-06-01-082553.md` | diff --git a/docs/H_DRIVE_NEARLINE_PULL.md b/docs/H_DRIVE_NEARLINE_PULL.md index d13d32b..48baaa2 100644 --- a/docs/H_DRIVE_NEARLINE_PULL.md +++ b/docs/H_DRIVE_NEARLINE_PULL.md @@ -12,6 +12,12 @@ Status: **produktiv** (2026-05-28). Erster echter Lauf 2026-05-27 20:45 erfolgre - `ops/h-drive-nearline/pull-critical-backups.ps1` excluded die `unraid-flash-config.*`-Familie ueber `/XF`, damit Flash-Config bewusst nicht in den Nearline-Scope kommt. - Zweiter Lauf (nach Fixes): beide Robocopy-Jobs Exit-Code 1, **19 Borg-Dumps + 10 Gitea-Bundle-Files** auf H:/. +## Befund 2026-06-01 + +- Der Scheduled Task um 05:30 kopierte die aktuellen Dumps, brach aber mit Robocopy Exit-Code 8 ab, weil im Dump-Root alte `*-pre-*` Dateien und Migration-/Cutover-Verzeichnisse mit restriktiven Rechten lagen. +- Fix: `ops/h-drive-nearline/pull-critical-backups.ps1` kopiert fuer `borg-dumps-latest` nur noch die kuratierte Pflichtdatei-Liste und schliesst Migration-/Cutover-Verzeichnisse aus. +- Manueller Kontrolllauf 2026-06-01 08:25 erfolgreich: `borg-dumps-latest` Exit-Code 0, `gitea-bundles` Exit-Code 1 (Robocopy-Erfolg mit Kopien), Report `H:\kallilab-nearline-backups\_reports\nearline-pull-2026-06-01-082553.md`. + ## Zweck `H:/` ist eine zweite lokale Nearline-Kopie fuer die wichtigsten Restore-Artefakte. Es ersetzt weder Hetzner/Borg noch ein echtes Off-site-/Airgap-Ziel, reduziert aber das Risiko, dass ein lokaler Restore nur vom Unraid-Array abhaengt. @@ -20,11 +26,13 @@ Status: **produktiv** (2026-05-28). Erster echter Lauf 2026-05-27 20:45 erfolgre | Zweck | Quelle | Ziel | |---|---|---| -| Aktuelle Dumps inklusive Flash-Backup | `\\192.168.178.58\backups\borg\dumps\latest` | `H:\kallilab-nearline-backups\borg-dumps\latest` | +| Aktuelle kuratierte Dumps ohne Flash-Backup | `\\192.168.178.58\backups\borg\dumps\latest` | `H:\kallilab-nearline-backups\borg-dumps\latest` | | Gitea-Bundles | `\\192.168.178.58\backups\git-bundles\gitea` | `H:\kallilab-nearline-backups\git-bundles\gitea` | Das Skript kopiert bewusst **nicht** mit `/MIR` und loescht keine Dateien auf `H:/`. Alte Artefakte duerfen dort erst nach manueller Sichtpruefung geloescht werden. +Der Borg-Dumps-Job ist eine Whitelist der aktuellen Nearline-Pflichtartefakte. Einmalige Migrations-Sicherungen, Pre-Major-Snapshots und Redis-Cutover-Verzeichnisse bleiben ueber Borg/Hetzner abgedeckt, sind aber kein H:/-Nearline-Pflichtbestand. + ## Skript ```powershell diff --git a/ops/h-drive-nearline/pull-critical-backups.ps1 b/ops/h-drive-nearline/pull-critical-backups.ps1 index ce54690..c227a06 100644 --- a/ops/h-drive-nearline/pull-critical-backups.ps1 +++ b/ops/h-drive-nearline/pull-critical-backups.ps1 @@ -17,13 +17,34 @@ $Jobs = @( # nicht ueberbruecken kann. Restore-Quelle dafuer bleibt das # Hetzner-Borg-Repo (siehe docs/RESTORE_MATRIX.md Tier 1 Unraid OS Flash). ExcludeFiles = @("unraid-flash-config.tar.gz", "unraid-flash-config.tar.gz.sha256", "unraid-flash-config.manifest.txt") + Files = @( + "borg-ui.sqlite", + "filebrowser.bolt.dump", + "gitea.sqlite.dump", + "grafana.sqlite", + "immich.dump", + "komodo-mongo.archive.gz", + "mealie.dump", + "nextcloud.dump", + "postgresql17-authelia.dump", + "postgresql17-globals.sql", + "postgresql17-mailarchiver.dump", + "postgresql17-paperless.dump", + "speedtest-tracker.sqlite.dump", + "vaultwarden.sqlite.dump" + ) + # Migration-/Cutover-Arbeitsverzeichnisse bleiben im Borg-Scope, sind aber + # keine Nearline-Pflichtartefakte und enthalten teils root-only Dateien. + ExcludeDirs = @(".tmp", "immich-vectorchord-*", "nextcloud-redis-pre-redis8-*", "pg18-major-*", "redis8-*", "shared-redis-pre-redis8-*") }, @{ Name = "gitea-bundles" Source = Join-Path $SourceRoot "git-bundles\gitea" Destination = Join-Path $DestinationRoot "git-bundles\gitea" Purpose = "Verified bare-repository bundles for Gitea bootstrap" + Files = @("*.*") ExcludeFiles = @() + ExcludeDirs = @(".tmp") } ) @@ -47,9 +68,17 @@ function Invoke-RobocopyJob { $logPath = Join-Path $LogRoot ("{0}-{1}.log" -f (Get-Date -Format "yyyyMMdd-HHmmss"), $Job.Name) New-Item -ItemType Directory -Force -Path $Job.Destination | Out-Null + $files = @("*.*") + if ($Job.ContainsKey("Files") -and $Job.Files.Count -gt 0) { + $files = $Job.Files + } + $args = @( $Job.Source, - $Job.Destination, + $Job.Destination + ) + $args += $files + $args += @( "/E", "/COPY:DAT", "/DCOPY:DAT", @@ -57,13 +86,16 @@ function Invoke-RobocopyJob { "/W:5", "/FFT", "/XJ", - "/XD", - ".tmp", "/NP", "/TEE", "/LOG:$logPath" ) + if ($Job.ContainsKey("ExcludeDirs") -and $Job.ExcludeDirs.Count -gt 0) { + $args += "/XD" + $args += $Job.ExcludeDirs + } + if ($Job.ContainsKey("ExcludeFiles") -and $Job.ExcludeFiles.Count -gt 0) { $args += "/XF" $args += $Job.ExcludeFiles