Szenario: VPS-Totalausfall
7 Phasen aus DR-Runbook. RTO mit OVH-Snapshot ~30 min; ohne Snapshot 4–8 h. Schritte abhaken (lokaler Browser-State, kein Server).
Passive only: Befehle werden NICHT vom Cockpit ausgeführt. Kopieren, in einer SSH-Session ausführen, Output prüfen.
0 OVH VPS-Snapshot zurückspielen (Plan A, 5–10 min) ~10 min
Schnellster Pfad. Setzt voraus, dass OVH-Snapshot von 04:43 bootet (NIE getestet — siehe GAP P0-3).
- OVH Manager öffnen (siehe Direct-Links).
- VPS
vps-405d22f5→ Backups → letzten Snapshot auswählen. - "Restore" anklicken. Wartezeit: 5–10 min.
- Wenn VPS bootet → Phase 6 (Verifizierung). Wenn nicht → Phase 1 unten.
PITR-Window und Retention sind in OVH Console UNDER ho113153 — siehe GAP P0-2.
1 Encryption-Keys zurückholen (Voraussetzung für ALLES) ~10 min
Ohne backup.key sind ALLE .age-Dateien wertlos.
Weg A — Bitwarden (bevorzugt):
- vault.bitwarden.com öffnen, Master-Password.
- Ordner "OYSI — Backups & DR" → Items "SOPS Key" + "Key-Bundle Passphrase".
- Inhalt auf den neuen VPS speichern (siehe Phase 2).
Weg B — Bundle aus OVH-S3 (Fallback, Bundle ist 35d alt):
# rclone-Creds aus Bitwarden Item "OVH-S3 rclone" einlesen
mkdir -p ~/.config/rclone && nano ~/.config/rclone/rclone.conf
rclone copy ovh-backup:adorable-powell/keys/keys-bundle.tar.gz.age .
age -d keys-bundle.tar.gz.age > keys-bundle.tar.gz # Passphrase aus Bitwarden
tar xzf keys-bundle.tar.gz -C /home/ubuntu/infrastructure/keys/
chmod 600 /home/ubuntu/infrastructure/keys/{sops,backup}.key Endergebnis: /home/ubuntu/infrastructure/keys/{sops.key,backup.key} existieren, Mode 600.
2 Basis-System aufsetzen ~15 min
sudo apt update && sudo apt install -y \
docker.io docker-compose-plugin age postgresql-client \
rclone git sops curl wget mailutils
sudo systemctl enable docker
sudo usermod -aG docker ubuntu
mkdir -p /home/ubuntu/infrastructure/{keys,secrets,backups,logs,pg-credentials,state/backup}
mkdir -p /home/ubuntu/services Backup-Disk (war /dev/sdb1 ext4 50 GB) bei OVH-Snapshot-Restore vorhanden; bei nacktem VPS via OVH Console → Additional Disk neu zuweisen + formatieren.
3 Repository klonen + Configs zurückholen ~5 min
Configs liegen primär in Git, das Config-Backup ist die Belt-and-Suspenders-Kopie.
cd /home/ubuntu && git clone git@github.com:oysi2025/infrastructure-repo.git .
# Wenn Git nicht erreichbar: Fallback Config-Tarball aus S3:
LATEST=$(rclone lsf ovh-backup:adorable-powell/configs/ | sort | tail -1)
rclone copy "ovh-backup:adorable-powell/configs/$LATEST" .
age -d -i /home/ubuntu/infrastructure/keys/backup.key -o configs.tar.gz "$LATEST"
mkdir -p /tmp/restore && tar xzf configs.tar.gz -C /tmp/restore/ 4 DBs zurückspielen (4a–4e)
4a — OVH Managed PG17 (überlebt VPS-Tod)
11 CloudDBs leben extern auf ho113153-001.eu.clouddb.ovh.net:35547. Nach VPS-Tod meist unverändert da.
- OVH Manager → Public Cloud → Databases → ho113153-001 → Status prüfen.
- Ggf. PITR auf Stand vor VPS-Crash. (Window UNKLAR — GAP P0-2.)
- Wenn DBs OK → keine Action, Services connecten direkt nach Service-Start.
4b — Wenn CloudDB korrupt: aus eigenen Dumps
# Pro DB:
age -d -i keys/backup.key -o finance.dump backups/clouddb/finance_20260430_*.dump.age
PGPASSWORD=... pg_restore -h ho113153-001.eu.clouddb.ovh.net -p 35547 \
-U finance_user -d finance --no-owner --no-acl finance.dump
# Credentials aus pg-credentials/*.enc.yaml (SOPS) — siehe Direct-Links 4c — ERPNext MariaDB (im Volume erp-db-data)
age -d -i keys/backup.key -o erpnext.sql.gz \
backups/erpnext/_8dd95132afac5d61_20260430_*.sql.gz.age
gunzip erpnext.sql.gz
docker compose -f services/erp/docker-compose.yml up -d mariadb
docker exec -i erp-mariadb mariadb -uroot -p"$ROOT_PWD" < erpnext.sql 4d — Docker Volumes (22 Stück)
# Pro Volume:
age -d -i keys/backup.key -o vol.tar.gz \
backups/volumes/20260430_030155/zammad_zammad-data.tar.gz.age
docker volume create zammad_zammad-data
docker run --rm -v zammad_zammad-data:/target -v "$PWD":/backup alpine \
sh -c 'cd /target && tar xzf /backup/vol.tar.gz' 4e — wg-easy SQLite
age -d -i keys/backup.key -o wg.db.gz backups/vpn/wg-easy-20260430.db.gz.age
gunzip wg.db.gz
mkdir -p /home/ubuntu/services/vpn/config
sudo cp wg.db /home/ubuntu/services/vpn/config/wg-easy.db
docker compose -f services/vpn/docker-compose.yml up -d wg-easy 5 Service-Start in Reihenfolge ~30 min
- Infrastructure (Traefik + Monitoring) —
infra-compose.service - Zammad (Support kritisch)
- EFSD (Garage S3, DGUV, Multi-Tenant Schule)
- Finance, Shipping, ERPNext (Geschäftskritisch)
- Restliche Services nach Bedarf
sudo systemctl start infra-compose.service
cd /home/ubuntu/services/zammad && ./compose-sops.sh up -d
cd /home/ubuntu/services/efsd && ./compose-sops.sh up -d
cd /home/ubuntu/services/finance && ./compose-sops.sh up -d
cd /home/ubuntu/services/shipping && ./compose-sops.sh up -d
cd /home/ubuntu/services/erp && ./compose-sops.sh up -d 6 Verifizierung ~15 min
- DNS:
dig vpn.oysi.techliefert die richtige IP. systemctl status backup-*.timer— alle aktiv.- Smoke:
curl -I https://traefik-internal/dashboard/ - Manueller Restore-Test:
/home/ubuntu/infrastructure/scripts/restore-test.sh
7 Bitwarden re-sync
/home/ubuntu/infrastructure/scripts/bitwarden-sync.sh --dry-run Dann ohne --dry-run, damit Bitwarden-Cloud-State == Server-State.