Files
homelab/doc/plan/migrations-backup-runbook.md
T

5.6 KiB

migrations-backup runbook — vor dem full-wipe

Ziel: alles sichern → verifizieren → NVMe + Tank wipen → Proxmox & Tank frisch nach Manifest → zurückspielen. Regel: solange das Backup nicht getestet ist, wird nichts gewiped. Nach dem Wipe gibt es keinen zpool import mehr — das Backup ist die einzige Kopie.

ausgangslage (aus deinen screenshots)

  • Root liegt auf local-lvm (LVM-Thin), nicht ZFS → Reinstall ist der einzige Weg zum ZFS-Root.
  • tank = ZFS-Mirror (die Bulk-Daten).
  • ext-hdd01 (/mnt/pve/ext-hdd01, Directory, Backup-fähig) = Backup-Ziel, überlebt den Wipe.

dein inventar

ID Name Typ Annahme: stateful?
100 nextcloud LXC DB + Files
101 immich LXC Postgres + Files
102 vaultwarden LXC Daten/SQLite
103 mailserver LXC KRITISCH — Mail + DB + DKIM
105 obsidian-livesync LXC CouchDB?
106 gitea LXC DB + Repos
107 openbureau LXC Postgres?
110 flarum LXC DB
111 nginx-proxy-manager LXC Config/Certs
200 kgva-website LXC meist statisch
210 openbureau-web LXC meist statisch
211 rapport-website LXC meist statisch
212 dossier-website LXC meist statisch
219 dev.openbureau LXC ?
220 trattoriamarina.ch LXC meist statisch
900 rapport-server LXC Postgres/Supabase?
500 windows VM grösster Brocken — Platz checken
800 homeassistant-os VM Config

Die „stateful?"-Spalte sind Annahmen — bitte bestätigen/korrigieren (siehe Schritt 0).


schritt 0 — discovery (mountpoints + backup-flags aufdecken)

# was ist wo gemountet, und ist backup=1 oder backup=0?
for id in $(pct list | awk 'NR>1{print $1}'); do
  echo "=== CT $id ==="; pct config $id | grep -E '^(rootfs|mp[0-9]+):'
done

# was liegt auf dem tank?
zfs list -r tank

# freier platz auf der backup-platte?
df -h /mnt/pve/ext-hdd01

Das zeigt, welche Daten schon in den vzdumps stecken (rootfs + backup=1-Mounts) und welche separat per Restic müssen (backup=0-Mounts auf dem Tank). → Diese Ausgabe brauche ich, um die exakten Restic-Pfade einzusetzen.


schritt 1 — stateful dienste app-level dumpen (portabel über den rebuild)

Macht die Wiederherstellung sauber unabhängig von Block-Konsistenz. Dumps in einen Pfad schreiben, der mitgesichert wird (rootfs oder ein backup=1-Mount).

  • 103 mailserver — sein eigenes Backup nutzen. Bei docker-mailserver: setup backup bzw. das Mailcow-Backup-Skript. DKIM-Keys + DNS-Records (SPF/DMARC/MX) separat notieren — der häufigste Migrations-Schmerz.
  • DB-Dienste (100/101/106/110/107/900 — je nach Engine):
    # Postgres (im docker-container):
    pct exec <id> -- docker exec <pg-container> pg_dumpall -U postgres > /pfad/dump.sql
    # MariaDB/MySQL:
    pct exec <id> -- docker exec <db-container> mysqldump --all-databases -uroot -p<pw> > /pfad/dump.sql
    
  • 102 vaultwarden / 105 obsidian-livesync — vor dem Sichern stoppen, dann ist der Datenstand konsistent.

schritt 2 — container + VMs sichern (vzdump → ext-hdd01)

Weil wir eh wipen, ist Downtime okay → --mode stop = sauber konsistent.

# alle CTs und VMs:
for id in $(pct list | awk 'NR>1{print $1}') $(qm list | awk 'NR>1{print $1}'); do
  vzdump $id --mode stop --compress zstd --storage ext-hdd01
done

Achtung: 500 (windows) ist vermutlich der grösste Brocken. Vorher df -h /mnt/pve/ext-hdd01 prüfen.


schritt 3 — tank-daten sichern (restic → ext-hdd01 UND hetzner)

Pfade aus Schritt 0 einsetzen. Zwei unabhängige Kopien, weil es nach dem Wipe die einzige Quelle ist.

export RESTIC_PASSWORD_FILE=/root/.restic-pw

# lokal auf die externe platte
export RESTIC_REPOSITORY=/mnt/pve/ext-hdd01/restic-tank
restic init
restic backup /tank/<dataset1> /tank/<dataset2> /tank/<...>

# offsite nach hetzner
export RESTIC_REPOSITORY=sftp:uXXXX@uXXXX.your-storagebox.de:/tank
restic init
restic backup /tank/<dataset1> /tank/<dataset2> /tank/<...>

Restic als root → Eigentümer/Rechte (inkl. Idmap-Offsets der Shares) kommen 1:1 zurück.


schritt 4 — verifizieren + restore-test (PFLICHT)

restic -r /mnt/pve/ext-hdd01/restic-tank check

# einen container testweise auf freie ID zurückholen:
pct restore 999 /mnt/pve/ext-hdd01/dump/vzdump-lxc-102-*.tar.zst --storage local-lvm
pct start 999      # läuft er? dann wieder weg:
pct stop 999 && pct destroy 999

# einen tank-pfad testweise restoren:
restic -r /mnt/pve/ext-hdd01/restic-tank restore latest --target /tmp/rtest --include /tank/<dataset>
ls -la /tmp/rtest/tank/<dataset>

schritt 5 — wipe-freigabe (erst wenn ALLES grün)

  • vzdump aller 18 Gäste auf ext-hdd01 vorhanden
  • Tank-Restic auf ext-hdd01 und Hetzner, restic check ok
  • DB-/Mail-Dumps vorhanden und im Backup enthalten
  • je 1 Container- und 1 Tank-Restore erfolgreich getestet
  • DKIM-Keys + DNS-Records notiert
  • beim Reinstall wird ext-hdd01 NICHT als Ziel gewählt

schritt 6 — nach dem rebuild: reihenfolge

  1. Proxmox neu auf NVMe, ZFS-root (rpool) — nur NVMe als Ziel.
  2. tank neu als Mirror + Datasets/Quotas nach Manifest.
  3. ext-hdd01 wieder mounten.
  4. Tank-Daten per restic restore zurück in die frischen Datasets.
  5. Container/VMs aus vzdump zurück: pct restore <id> <file> --storage ... bzw. qmrestore <file> <id> für die VMs. Dabei kannst du gleich auf das neue Manifest-Schema umnummerieren.
  6. mailserver zuletzt und mit Ruhe; DKIM/DNS prüfen, Testmail.
  7. PBS + sanoid + Restic als laufendes System einrichten (permanentes Backup).