Server Backups
Server Backups
Section titled “Server Backups”Verschlüsselte, deduplizierende, inkrementelle Backups mit
restic. Funktioniert mit S3, SFTP, Hetzner Storage Box, lokaler Platte, Backblaze B2. Retention wird server-seitig durchgesetzt, nicht durch Cron-Logs.
Quick-Links: Server erstinstallation Phase 9 · Server härten
Warum restic und nicht tar+rsync
Section titled “Warum restic und nicht tar+rsync”| Kriterium | tar/rsync |
restic |
|---|---|---|
| Verschlüsselung at-rest | ❌ selbst basteln | ✅ AES-256, Repo selbst ist Krypto-blob |
| Deduplizierung | ❌ jedes Backup Vollkopie | ✅ Content-defined Chunking |
| Inkrementelle Snapshots | manuell (rsync –link-dest) | ✅ nativ |
| Retention (“behalte letzte 7, 4 weekly, 6 monthly”) | Cron + Logik selbst | ✅ forget --keep-* |
| Restore in ein beliebiges Verzeichnis | ✅ | ✅ |
| Tooling-Komplexität | niedrig | mittel |
| Doku & Community | — | ✅ sehr aktiv |
Für private Setups ist restic fast immer die richtige Wahl. borg ist die Alternative mit ähnlichem Funktionsumfang — wenn du Borg kennst, bleib dabei.
Backup-Ziel wählen
Section titled “Backup-Ziel wählen”| Ziel | Kosten | Geschwindigkeit | Empfehlung |
|---|---|---|---|
| Hetzner Storage Box | ~3.50 €/Monat (1 TB) | Gigabit | ✅ Standard für EU-Server |
| Backblaze B2 | $0.005/GB/Monat | schnell | ✅ wenn >5 TB oder US-nähe |
| S3 (AWS, Hetzner, Contabo) | variiert | schnell | ✅ in Stack integriert |
| Zweite Platte / NFS lokal | kostenlos | sehr schnell | ⚠️ zählt nicht als “off-site” — Brand/RAID-Ausfall = weg |
| rsync.net | variiert | mittel | ❌ overkill für Privat |
Für diese Anleitung: SFTP-Backend (Hetzner Storage Box, oder beliebiger SSH-Server).
Phase 1: Installation + Repo initialisieren
Section titled “Phase 1: Installation + Repo initialisieren”sudo apt install resticrestic version# restic 0.16.x oder neuerRepository-Initialisierung (einmalig pro Server × Ziel-Kombination):
# Storage-Box oder SFTP-Server als Zielexport RESTIC_REPOSITORY="sftp:backup@backup.example.com:/srv/backups/server-01"export RESTIC_PASSWORD_FILE="/root/.config/restic/passphrase"
# Passphrase generieren, sicher ablegen (auf dem Server, NICHT im Repo!)mkdir -p /root/.config/resticchmod 700 /root/.config/resticopenssl rand -hex 32 | sudo tee /root/.config/restic/passphrasechmod 600 /root/.config/restic/passphrase
# Repo initialisierenrestic init# "created restic repository ... at sftp:..."# "Please note that knowledge of your password is required ..."⚠️ Die Passphrase ist der einzige Schlüssel. Verlierst du sie, sind die Backups mathematisch unknackbar. Backup der Passphrase in einem Passwort-Manager (1Password/Bitwarden/KeePass) ablegen.
Phase 2: Erster Backup
Section titled “Phase 2: Erster Backup”# Was soll gesichert werden?restic backup /etc /home /var/log /root /opt /var/www
# Schnell prüfen, was drin istrestic snapshots# ID Time Host Tags# --------------------------------------------------------------# a1b2c3d4 2026-07-02 03:00:00 server-01Phase 3: Backup-Skript + Cron
Section titled “Phase 3: Backup-Skript + Cron”/usr/local/bin/backup-restic.sh:
#!/usr/bin/env bashset -euo pipefail
export RESTIC_REPOSITORY="sftp:backup@backup.example.com:/srv/backups/server-01"export RESTIC_PASSWORD_FILE="/root/.config/restic/passphrase"
# Was sichern? Server-spezifisch anpassenPATHS="/etc /home /var/log /root /opt /var/www"
# Retention: 7 täglich, 4 wöchentlich, 6 monatlichrestic backup $PATHSrestic forget \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 6 \ --prune
# Healthcheck: Repo-Konsistenzrestic check
# Mail bei Fehler (optional, braucht mailutils + SMTP)if [ $? -ne 0 ]; then echo "Backup-Fehler auf $(hostname)" | mail -s "BACKUP FAIL $(hostname)" admin@example.comfisudo chmod 700 /usr/local/bin/backup-restic.sh
# Cron: täglich 03:00sudo crontab -e# 0 3 * * * /usr/local/bin/backup-restic.sh >> /var/log/restic-backup.log 2>&1Phase 4: Restore üben (PFLICHT)
Section titled “Phase 4: Restore üben (PFLICHT)”Ein Backup, das nie restored wurde, ist kein Backup. Teste vor dem ersten produktiven Einsatz, und alle 3-6 Monate.
# In Test-Verzeichnis restoren (überschreibt nichts im Live-System)restic restore latest --target /tmp/restore-testls /tmp/restore-test/etcls /tmp/restore-test/home# Verzeichnisse da? Inhalt plausibel?
# Einzelne Datei rausziehen (häufigster Use-Case)restic restore latest --target /tmp/restore-test \ --include /etc/nginx/nginx.confcat /tmp/restore-test/etc/nginx/nginx.conf
# Bestimmtes Verzeichnisrestic restore latest --target /tmp/restore-test \ --include /var/wwwRestore auf einen anderen Server (Disaster-Recovery-Szenario):
# Auf neuem Server:apt install restic# Passphrase + Repo-URL konfigurieren (aus Passwort-Manager kopieren)restic -r sftp:backup@backup.example.com:/srv/backups/server-01 snapshotsrestic -r sftp:backup@backup.example.com:/srv/backups/server-01 restore latest \ --target /restorePhase 5: Monitoring (optional)
Section titled “Phase 5: Monitoring (optional)”Exit-Code per Cron überwachen
Section titled “Exit-Code per Cron überwachen”# /usr/local/bin/backup-restic.sh erweitern:EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then # systemd-notify, Mail, Telegram, etc. curl -s -X POST https://api.telegram.org/bot<TOKEN>/sendMessage \ -d chat_id=<CHAT_ID> \ -d text="🚨 Backup failed on $(hostname): exit $EXIT_CODE"fiHealthcheck via restic check
Section titled “Healthcheck via restic check”Cron: wöchentlich restic check einplanen (Repo-Konsistenz).
# In backup-restic.sh oder separater Cronjob:restic check# liest alle Pack-Files und validiert StrukturAlter des letzten Snapshots monitoren
Section titled “Alter des letzten Snapshots monitoren”LAST=$(restic snapshots --json | jq -r '.[-1].time')AGE_HOURS=$(( ( $(date +%s) - $(date -d "$LAST" +%s) ) / 3600 ))[ $AGE_HOURS -gt 26 ] && echo "ALARM: letztes Backup älter als 26h"Phase 6: Retention verstehen
Section titled “Phase 6: Retention verstehen”restic forget löscht Snapshots gemäß Policy, restic prune räumt ungenutzte Daten weg (langsam, speicherintensiv).
Beispiel-Kurven:
--keep- |
Beispiel | Effekt |
|---|---|---|
daily 7 |
7 tägliche Snapshots | letztes Backup + 6 Tage davor |
weekly 4 |
4 wöchentliche | letzte Woche + 3 davor |
monthly 6 |
6 monatliche | Halbes Jahr Rückblick |
yearly 10 |
10 jährliche | für Compliance |
Reihenfolge zählt: --keep-daily zuerst, dann --keep-weekly (die “ältesten” wöchentlichen, die noch keine Daily-Vertretung haben), etc.
Phase 7: Best Practices
Section titled “Phase 7: Best Practices”Was rein soll
Section titled “Was rein soll”/etc— Konfiguration (oft vergessen!)/home— User-Daten/var/wwwoder App-Verzeichnisse/opt— selbst-installierte Software/var/log— Logs (für Post-Mortem nach Crash)/root— root’s Home (Scripts, SSH-Config)
Was NICHT rein soll
Section titled “Was NICHT rein soll”/proc,/sys,/dev,/tmp,/run— Pseudo-Dateisysteme/var/cache— kannst du neu erzeugen- Großer Müll (
/var/lib/docker/overlay2,/var/lib/libvirt) — Repo-Killer, separat behandeln
Excludes
Section titled “Excludes”restic backup /var/www \ --exclude='*.log' \ --exclude='node_modules' \ --exclude='.cache'Backup vor Server-Migration
Section titled “Backup vor Server-Migration”# Snapshot vor Migrationrestic backup /etc /home /var/log /root /opt /var/wwwrestic snapshots# → letzte Snapshot-ID notieren# Server migrieren# Auf neuem Server: restore + Repo initialisiert lassenRepository-Migration (z.B. Storage-Box-Anbieter-Wechsel)
Section titled “Repository-Migration (z.B. Storage-Box-Anbieter-Wechsel)”# Repo A: SFTP altexport RESTIC_REPOSITORY="sftp:backup@old.example.com:/srv/backups"export RESTIC_PASSWORD_FILE="/root/.config/restic/passphrase"restic snapshots
# Repo B: B2 neu initialisierenexport RESTIC_REPOSITORY="b2:bucket-name:server-01"export B2_ACCOUNT_ID="..."export B2_ACCOUNT_KEY="..."restic init
# Snapshots von A nach B kopieren (ohne neuen Backup-Run)restic copy --repo2 sftp:backup@old.example.com:/srv/backups# ODER: restic migrate (nur wenn Repo-Format-Versionen abweichen)Troubleshooting
Section titled “Troubleshooting”| Problem | Ursache | Fix |
|---|---|---|
Fatal: unable to open config file |
falsche Repo-URL oder kein Zugriff | restic snapshots mit expliziten ENV-Variablen testen |
Fatal: parse error |
Repo-Format-Version mismatch | restic migrate ausführen |
repository is locked |
vorheriger Run nicht sauber beendet | restic unlock |
| Snapshot dauert ewig | erstes Backup, viel Daten | --one-file-system + --exclude-caches nutzen, Repo-Größe überwachen |
Repo wächst trotz forget |
prune vergessen |
immer forget --prune zusammen |
check findet Fehler |
Bitrot / Netzwerk-Issue | restic repair snapshots + restic repair packs (nicht ohne Backup-Passphrase) |
Wenn’s ernst wird: Disaster Recovery
Section titled “Wenn’s ernst wird: Disaster Recovery”- Panik bleibt aus. Du hast die Passphrase im Passwort-Manager.
- Neuen Server provisionieren (gleicher Cloud-Provider oder anderer).
- Restic installieren, Passphrase + Repo-URL setzen.
restic snapshots→ aktuellste Snapshot-ID wählen.restic restore latest --target /oder nur die kritischen Pfade.- Dienste neu starten (Docker, systemd, was auch immer).
- Backups auf neuem Server neu einrichten (gleiche Cron-Jobs).
- Post-Mortem: was war kaputt, warum hat es nicht früher angekündigt?