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

149 lines
5.6 KiB
Markdown

# 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)
```bash
# 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):
```bash
# 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.
```bash
# 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.
```bash
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)
```bash
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).