PostgreSQL Backup-Strategie: Automatische Backups einrichten
Backups sind eines der Themen, bei denen die Lücke zwischen "machen wir mal" und "funktioniert tatsächlich" besonders groß ist. Ich habe in den letzten Jahren mit zwei Datenverlust-Szenarien zu tun gehabt — einmal eigene Datenbank, einmal die eines Freundes. In beiden Fällen gab es nominell Backups. In beiden Fällen waren sie nicht wiederherstellbar.
Daraus habe ich gelernt, dass eine Backup-Strategie aus zwei Teilen besteht: dem Backup selbst und dem regelmäßigen Restore-Test. Den zweiten Teil überspringen die meisten.
Das absolute Minimum
pg_dump für eine einzelne Datenbank, in eine Datei mit Datum:
#!/bin/bash
set -euo pipefail
BACKUP_DIR=/var/backups/postgres
mkdir -p "$BACKUP_DIR"
DATE=$(date +%Y%m%d-%H%M%S)
pg_dump -Fc -U postgres app > "$BACKUP_DIR/app-$DATE.dump"
-Fc ist das Custom-Format, komprimiert und mit pg_restore selektiv wiederherstellbar. Plain SQL (-Fp) lässt sich mit weniger Tools öffnen, ist aber bei jedem Restore eine 1:1-Replay-Aktion — keine Möglichkeit, einzelne Tabellen rauszupicken.
Für mehrere Datenbanken auf einem Cluster: pg_dumpall für die globalen Objekte (Users, Roles), dann pro Datenbank ein einzelner pg_dump. Wer alles in einen großen Dump steckt, verliert die Granularität.
Rotation, damit der Server nicht volläuft
Naive Rotation ist eine Fehlerquelle. Ich habe einmal ein Backup-Script gehabt, das find -mtime +30 -delete nutzte — funktionierte, bis Cron einen Tag ausfiel. Beim nächsten Lauf waren genau die Backups gelöscht, die ich gebraucht hätte.
Mein aktuelles Schema folgt grob der Großvater-Vater-Sohn-Logik:
- 7 tägliche Backups
- 4 wöchentliche
- 6 monatliche
Implementiert mit benannten Verzeichnissen statt mtime:
DAY=$(date +%u)
WEEK=$(date +%V)
MONTH=$(date +%m)
pg_dump -Fc -U postgres app > "$BACKUP_DIR/daily-$DAY.dump"
if [[ $(date +%u) -eq 7 ]]; then
cp "$BACKUP_DIR/daily-$DAY.dump" "$BACKUP_DIR/weekly-$WEEK.dump"
fi
if [[ $(date +%d) -eq 01 ]]; then
cp "$BACKUP_DIR/daily-$DAY.dump" "$BACKUP_DIR/monthly-$MONTH.dump"
fi
Das Schöne daran: alte Backups werden überschrieben statt gelöscht. Nichts wird "vergessen", nichts läuft voll.
Off-Site, sonst sind's keine Backups
Ein Backup auf demselben Server wie die Datenbank ist nicht wirklich ein Backup. Wenn der Server abraucht, ist beides weg. Ich kopiere meine Dumps zusätzlich per rsync auf einen zweiten VPS und in einen S3-kompatiblen Storage:
rsync -az "$BACKUP_DIR/" backup-server:/var/backups/db/
# Hetzner Storage Box, aber jeder S3-Provider geht
rclone sync "$BACKUP_DIR" remote:db-backups/
rclone mit Verschlüsselung dazwischen, damit der Storage-Provider die Inhalte nicht sieht.
Cron, der nicht still scheitert
Klassischer Cron-Eintrag für 3 Uhr morgens:
0 3 * * * /usr/local/bin/pg-backup.sh 2>&1 | logger -t pg-backup
logger -t pg-backup schreibt den Output in syslog mit einem Tag. Dadurch landet er im Standard-Log und kann von Logwatch o.ä. picked up werden.
Das Wichtige: kein > /dev/null. Wenn was schiefgeht, will ich es sehen. Ich pipe die Ausgabe zusätzlich an einen mailx-Trigger, der mich nur bei Exit-Code != 0 anpingt.
Restore testen, regelmäßig
Das hier ist der Teil, der bei Anleitungen meist fehlt. Backups sind nicht real, bis sie restored wurden.
Mein Test-Script:
#!/bin/bash
set -euo pipefail
LATEST=$(ls -t /var/backups/postgres/daily-*.dump | head -1)
TEST_DB="restore_test_$(date +%s)"
createdb -U postgres "$TEST_DB"
pg_restore -U postgres -d "$TEST_DB" "$LATEST"
ROW_COUNT=$(psql -U postgres -d "$TEST_DB" -tAc "SELECT count(*) FROM users")
dropdb -U postgres "$TEST_DB"
if [[ $ROW_COUNT -lt 1 ]]; then
echo "WARNUNG: Restore enthält keine User"
exit 1
fi
Läuft bei mir wöchentlich, mailt mir Erfolg oder Fehler. Hat einmal ein Problem gefunden — eine pg_dump-Version-Mismatch, die im normalen Backup-Lauf still einen warning-only-Dump produzierte, der beim Restore aber inkonsistent war.
Point-in-Time Recovery — wenn's wirklich wichtig ist
Für Production-Datenbanken mit Compliance-Anforderungen reicht pg_dump nicht. Da brauchst du WAL-Archivierung mit pgBackRest oder Barman. Damit kannst du auf jeden beliebigen Zeitpunkt zurück, nicht nur auf den nächsten Backup-Schnappschuss.
Für Hobby-Projekte und kleinere Apps ist das overkill. Tägliche Dumps mit Restore-Test reichen — solange du den Restore-Test wirklich machst.