Validate backup follow-up and harden nearline pull

This commit is contained in:
2026-06-01 08:27:52 +02:00
parent 4e34582008
commit c3222e800b
5 changed files with 53 additions and 7 deletions
+6 -2
View File
@@ -1,6 +1,6 @@
# AI Context # AI Context
Stand: 2026-05-31 Stand: 2026-06-01
Kurzer Kontext fuer KI-Agenten. Nicht als Ersatz fuer die echten Runbooks lesen. 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: Kurzfassung:
- naechsten Borg-Lauf nach den Dumps vom 2026-05-31 21:42 bestaetigen
- Alt-Volumes fruehestens ab 2026-06-02 freigeben - Alt-Volumes fruehestens ab 2026-06-02 freigeben
- Hetzner-Account-Hygiene und Borg `append-only` pruefen - Hetzner-Account-Hygiene und Borg `append-only` pruefen
- FRITZ!Box-Servicefenster fuer Update, Config-Backup und IPv6-Exposure planen - FRITZ!Box-Servicefenster fuer Update, Config-Backup und IPv6-Exposure planen
- Auth-/OIDC-/CrowdSec-/Hermes-Themen bewusst geparkt - 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.
+2 -1
View File
@@ -7,7 +7,6 @@ Audit-Snapshots wurden aus der Arbeitskopie entfernt; Detailhistorie liegt in Gi
| Prioritaet | Punkt | Naechster Schritt | | 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 | | 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 | 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 | | 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 ## 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. - Immich-, Paperless-, Gitea- und Vaultwarden-Restore-Pfade sind belegt.
- H:/ Nearline-Pull laeuft seit 2026-05-28 als Windows Scheduled Task. - H:/ Nearline-Pull laeuft seit 2026-05-28 als Windows Scheduled Task.
- FRITZ!Box-Portfreigaben sind bereinigt: WAN-seitig bleibt `443/tcp`. - FRITZ!Box-Portfreigaben sind bereinigt: WAN-seitig bleibt `443/tcp`.
+1
View File
@@ -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-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-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-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` |
+9 -1
View File
@@ -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. - `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:/. - 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 ## 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. `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 | | 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` | | 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. 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 ## Skript
```powershell ```powershell
+35 -3
View File
@@ -17,13 +17,34 @@ $Jobs = @(
# nicht ueberbruecken kann. Restore-Quelle dafuer bleibt das # nicht ueberbruecken kann. Restore-Quelle dafuer bleibt das
# Hetzner-Borg-Repo (siehe docs/RESTORE_MATRIX.md Tier 1 Unraid OS Flash). # 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") 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" Name = "gitea-bundles"
Source = Join-Path $SourceRoot "git-bundles\gitea" Source = Join-Path $SourceRoot "git-bundles\gitea"
Destination = Join-Path $DestinationRoot "git-bundles\gitea" Destination = Join-Path $DestinationRoot "git-bundles\gitea"
Purpose = "Verified bare-repository bundles for Gitea bootstrap" Purpose = "Verified bare-repository bundles for Gitea bootstrap"
Files = @("*.*")
ExcludeFiles = @() 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) $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 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 = @( $args = @(
$Job.Source, $Job.Source,
$Job.Destination, $Job.Destination
)
$args += $files
$args += @(
"/E", "/E",
"/COPY:DAT", "/COPY:DAT",
"/DCOPY:DAT", "/DCOPY:DAT",
@@ -57,13 +86,16 @@ function Invoke-RobocopyJob {
"/W:5", "/W:5",
"/FFT", "/FFT",
"/XJ", "/XJ",
"/XD",
".tmp",
"/NP", "/NP",
"/TEE", "/TEE",
"/LOG:$logPath" "/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) { if ($Job.ContainsKey("ExcludeFiles") -and $Job.ExcludeFiles.Count -gt 0) {
$args += "/XF" $args += "/XF"
$args += $Job.ExcludeFiles $args += $Job.ExcludeFiles