
Linux Firewall mit nftables 2026 – Modernes Setup
Linux Firewall mit nftables 2026: Modernes Setup mit Sets, Maps, NAT und Docker-Integration – inkl. Migration von iptables, Performance-Werten und Praxis-Befehl
PostgreSQL 17 und 18 haben das Backup-Ökosystem spürbar verändert. Inkrementelle pg_basebackup-Backups (ab PG 17) senken den Speicherbedarf drastisch, zstd-Kompression ist seit PG 16 nativ in pg_dump und pg_basebackup integriert, und pg_verifybackup prüft Backups inzwischen blockgenau gegen Manifest-Dateien. Wer noch mit pg_dump | gzip aus einem 2019er-Cronjob arbeitet, verschenkt Faktor 3 bis 5 bei Laufzeit und Speicher.
Gleichzeitig sind die Anforderungen gestiegen. Ein typischer Webshop mit 400 GB Datenbank und 2000 Schreibtransaktionen pro Sekunde produziert 8 bis 25 GB WAL pro Tag. Ein reines Nachtbackup bedeutet im Worst Case 24 Stunden Datenverlust – bei Bestellungen, Zahlungen und Buchungen ist das geschäftsschädigend. Die relevante Frage lautet deshalb nicht „Wie oft sichere ich?", sondern „Wie viel Datenverlust kostet mich eine Stunde Stillstand?"
Dazu kommt der Faktor Mensch. In Auswertungen von Post-Mortems aus 2024 und 2025 waren über 60 % der schweren Datenverluste auf nicht getestete oder unvollständige Backups zurückzuführen – nicht auf Hardware-Ausfälle. Ein Backup, das nie restored wurde, ist eine Hypothese. Deshalb gehört in jede Strategie ein regelmäßiger Restore-Drill, idealerweise automatisiert in einer Staging-Umgebung.
Bevor du einen einzigen Befehl tippst, definiere zwei Kennzahlen. RPO (Recovery Point Objective) beschreibt, wie viel Datenverlust akzeptabel ist – 5 Minuten, 1 Stunde, 24 Stunden. RTO (Recovery Time Objective) beschreibt, wie lange die Wiederherstellung dauern darf. Beide Werte bestimmen direkt, welche Methode du brauchst.
| Methode | RPO | RTO (100 GB) | Speicherbedarf | Einsatz |
|---|---|---|---|---|
| pg_dump (logisch) | 24 h | 45–90 min | 1× DB-Größe | Migrationen, kleine DBs |
| pg_basebackup + WAL | 1–5 min | 20–40 min | 1× DB + WAL | Standard-Produktion |
| pgBackRest Full+Incr | 1 min | 15–30 min | 0,3× DB + WAL | Enterprise, große DBs |
| Streaming Replica | ~0 | 2–5 min | 1× DB | HA, kein Backup-Ersatz |
Wichtig: Eine Streaming-Replica ist kein Backup. Ein versehentliches DELETE FROM orders; wird binnen Millisekunden repliziert. Replikation schützt gegen Hardwareausfall, nicht gegen Logikfehler. Du brauchst beides: Replikation für Verfügbarkeit, WAL-Archiv für Rücksetzbarkeit.
Für die meisten Produktionssysteme ab 50 GB ist die Kombination wöchentliches Full-Backup + tägliche inkrementelle Backups + kontinuierliche WAL-Archivierung der Goldstandard. Damit erreichst du einen RPO von unter 5 Minuten und einen RTO, der nur von der Restore-Bandbreite abhängt.
pg_dump bleibt das Werkzeug der Wahl für logische Backups, Versionsmigrationen und einzelne Tabellen. Der entscheidende Punkt: Nutze niemals das Plain-Format für Produktionsbackups. Das Custom-Format (-Fc) erlaubt selektiven Restore, paralleles Entpacken und native Kompression.
# Custom-Format mit zstd-Level 3 (PG 16+), 8 parallele Worker
pg_dump -h 10.0.0.5 -U backup_user -d shopdb \
-Fd -j 8 --compress=zstd:3 \
-f /backup/shopdb_$(date +%F_%H%M)
# Einzelne Tabelle, Custom-Format
pg_dump -Fc -t public.orders -d shopdb -f orders.dump
# Schema-only für Migrationsvergleiche
pg_dump -Fc --schema-only -d shopdb -f shopdb_schema.dump
Das Directory-Format (-Fd) mit -j 8 ist bei großen Datenbanken der Gamechanger. Eine 500-GB-Datenbank, die sequenziell 3,5 Stunden braucht, ist mit 8 Workern in 35 bis 50 Minuten gesichert – vorausgesetzt, die CPU und das Ziel-Storage machen mit. Achte darauf, dass -j nicht mehr Worker startet als CPU-Kerne verfügbar sind.
Ein häufiger Fehler ist der fehlende Konsistenz-Snapshot bei parallelen Dumps. Ab PostgreSQL 9.2 nutzt -j automatisch einen exportierten Snapshot, sodass alle Worker denselben Datenstand sehen. Das funktioniert aber nur, wenn alle Verbindungen zur selben Datenbank gehen – bei pg_dumpall mit mehreren Datenbanken ist das nicht der Fall.
Für die Kompression gilt: zstd:3 ist der beste Kompromiss. Gegenüber gzip -6 sparst du rund 40 % Laufzeit bei etwa 5 % größerer Ausgabe. Bei archivierten Backups auf S3 oder Storage Box lohnt sich zusätzlich zstd:9, wenn die CPU-Last nachts ohnehin niedrig ist.
Der klassische Albtraum: Das Backup wird erfolgreich restored, aber niemand kann sich anmelden, weil Rollen, Passwörter und Tablespaces fehlen. pg_dump sichert nur eine Datenbank und keine globalen Objekte. Rollen, Grants auf Cluster-Ebene und Tablespace-Definitionen liegen außerhalb.
# Nur Rollen und Globals – schnell, klein, kritisch
pg_dumpall --roles-only -h 10.0.0.5 -U postgres -f /backup/roles_$(date +%F).sql
# Alle Datenbanken inkl. Globals (bei parallelen Dumps ungeeignet)
pg_dumpall -h 10.0.0.5 -U postgres --clean --if-exists -f /backup/all.sql
Sichere die Rollen-Datei täglich, nicht wöchentlich. Sie ist nur wenige Kilobyte groß und ändert sich oft durch neue Service-Accounts oder CI-Runner. Bewahre sie zusätzlich in einem separaten Bucket mit anderer Zugriffskontrolle auf – wer die Rollendatei hat, kennt alle Benutzernamen und kann Passwort-Hashes analysieren.
Ein bewährtes Muster ist ein dreiteiliges Backup-Set: roles.sql (Globals), shopdb.dump (Datenbank-Inhalt) und wal/ (Archiv). Alle drei gehören in dasselbe Wiederherstellungs-Runbook, sonst scheitert der Restore an Schritt 2.
Ein Restore ist kein einzelner Befehl, sondern eine Sequenz. Bei einem vollständigen Wiederaufbau gehst du so vor:
postgresql.conf mit identischen shared_buffers, max_connections und Collation aufsetzen.roles.sql einspielen: psql -f roles.sql postgrescreatedb -O shopdb_owner shopdbANALYZE laufen lassen.# Paralleler Restore, ohne Owner/Privileges (Rollen sind schon da)
pg_restore -h 10.0.0.5 -U postgres -d shopdb \
-j 8 --no-owner --no-privileges --exit-on-error -v \
/backup/shopdb_2026-03-14_0200
# Nur eine Tabelle aus dem Dump extrahieren
pg_restore -d shopdb -t orders --data-only -j 4 shopdb.dump
Der Parameter --exit-on-error ist im Wiederherstellungsfall Pflicht. Ohne ihn ignoriert pg_restore Fehler und meldet am Ende „finished with warnings" – ein Zustand, der schon viele Teams in falscher Sicherheit gewiegt hat. Bei einem Restore in eine bestehende Datenbank willst du dagegen --clean --if-exists verwenden.
Für Performance: Deaktiviere während des Restores synchronous_commit, erhöhe maintenance_work_mem auf 2 GB und max_wal_size auf 16 GB. Das verkürzt einen 200-GB-Restore typischerweise von 90 auf 35 Minuten. Danach nicht vergessen, die Werte wieder zurückzusetzen.
Die WAL-Archivierung ist das Fundament jeder PITR-Fähigkeit. Ohne sie gibt es keinen Rücksetzpunkt zwischen zwei Backups. Die Grundkonfiguration in postgresql.conf:
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /mnt/wal_archive/%f && cp %p /mnt/wal_archive/%f'
archive_timeout = 60
wal_compression = zstd
archive_timeout = 60 erzwingt einen WAL-Segment-Wechsel spätestens nach 60 Sekunden, auch wenn das 16-MB-Segment nicht voll ist. Damit begrenzt du den RPO auf etwa eine Minute. Ohne diesen Wert kann ein Segment bei ruhiger Datenbank Stunden unvollständig bleiben.
Das test ! -f im archive_command ist kein Zierrat: PostgreSQL ruft das Kommando bei Fehlschlag erneut auf. Ohne die Prüfung überschreibt cp bestehende Segmente und du zerstörst dein Archiv stillschweigend. Prüfe den Archivstatus regelmäßig:
SELECT archived_count, failed_count, last_archived_wal, last_failed_wal
FROM pg_stat_archiver;
Ein failed_count größer 0 bedeutet: Das Archiv hat Lücken. Solche Lücken machen PITR unmöglich – und man merkt es oft erst im Notfall. Setze ein Monitoring auf diese View, mit Alarm bei jedem fehlgeschlagenen Archivierungsversuch.
PITR bedeutet: Du spielst ein Basisbackup ein und rechnest anschließend WAL-Segmente bis zu einem exakten Zeitpunkt nach. Das ist der Moment, in dem du sagen kannst: „Setze den Cluster auf 09:42:00 Uhr zurück, drei Minuten vor dem fehlerhaften Deployment."
# 1. Basisbackup entpacken
tar -xzf /backup/base_2026-03-13.tar.gz -C /var/lib/postgresql/17/main
# 2. Recovery-Konfiguration in postgresql.conf
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_time = '2026-03-14 09:42:00+01'
recovery_target_action = 'promote'
# 3. Recovery-Signal setzen (PG 12+)
touch /var/lib/postgresql/17/main/recovery.signal
# 4. Starten
pg_ctl -D /var/lib/postgresql/17/main start
Ab PostgreSQL 12 steuert recovery.signal den Recovery-Modus – recovery.conf existiert nicht mehr. Der Parameter recovery_target_action = 'promote' sorgt dafür, dass der Cluster nach Erreichen des Ziels in den Normalbetrieb wechselt und Schreibzugriffe akzeptiert. Alternativen sind 'pause' für manuelle Kontrolle oder 'shutdown' für forensische Analysen.
Für granulare Rücksetzpunkte kannst du benannte Markierungen verwenden: SELECT pg_create_restore_point('before_migration_2026_03_14'); und dann mit recovery_target_name darauf zurücksetzen. Das ist deutlich robuster als Zeitstempel, weil du keine Zeitzonen- und Uhrenprobleme hast.
Ein wichtiger Praxishinweis: Teste PITR mindestens quartalsweise auf einem separaten Host. Die häufigsten Fehlerquellen sind fehlende WAL-Segmente an Segmentgrenzen, falsche Berechtigungen im Archivverzeichnis und abweichende PostgreSQL-Minor-Versionen zwischen Backup und Zielcluster.
pg_basebackup kopiert den gesamten Cluster auf Dateiebene. Es ist schneller als pg_dump und liefert die exakte Grundlage für PITR.
# Vollständiges Basisbackup mit WAL-Streaming und Recovery-Config
pg_basebackup -h 10.0.0.5 -U replicator \
-D /backup/base_2026-03-14 \
-Fp -Xs -P -R --checkpoint=fast \
--compress=server-zstd:3
# Ab PG 17: inkrementelles Basisbackup
pg_basebackup -h 10.0.0.5 -U replicator \
-D /backup/base_incr_2026-03-15 \
-Fp -Xs -P --incremental=/backup/base_2026-03-14/backup_manifest
Die inkrementellen Basisbackups ab PostgreSQL 17 sind der größte Fortschritt seit Jahren. Statt täglich 500 GB zu kopieren, sicherst du nur die seit dem letzten Backup geänderten Blöcke – typischerweise 5 bis 20 GB pro Tag. Bei S3-Kosten von 0,023 USD pro GB summiert sich das schnell auf dreistellige Eurobeträge pro Jahr.
Verifiziere jedes Basisbackup mit pg_verifybackup. Das Tool prüft jede Datei gegen das Manifest und erkennt Bit-Rot, abgebrochene Transfers und Manipulation:
pg_verifybackup /backup/base_2026-03-14
Für Produktionsumgebungen solltest du pg_dump-Skripte durch ein dediziertes Backup-Tool ersetzen. pgBackRest ist 2026 der De-facto-Standard: Es unterstützt parallele Kompression, inkrementelle und differentielle Backups, S3-Repositories, Retention-Policies und Verschlüsselung out of the box.
# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=4
repo1-retention-diff=14
repo1-cipher-type=aes-256-cbc
compress-type=zstd
compress-level=6
[main]
pg1-path=/var/lib/postgresql/17/main
# Betrieb
pgbackrest --stanza=main stanza-create
pgbackrest --stanza=main --type=full backup
pgbackrest --stanza=main --type=incr backup
pgbackrest --stanza=main info
Für PITR mit pgBackRest genügt ein Befehl, inklusive automatischem WAL-Abruf:
pgbackrest --stanza=main --delta \
--type=time --target="2026-03-14 09:42:00+01" \
--target-action=promote restore
WAL-G ist die leichtere Alternative, wenn du ausschließlich in S3 oder kompatible Objektspeicher sicherst. Es ist in Go geschrieben, hat keine Abhängigkeiten und eignet sich gut für Kubernetes-Umgebungen mit CloudNativePG oder Zalando Postgres Operator.
Ein Backup ohne Verifikation ist eine Vermutung. Baue drei Prüfstufen ein. Erstens: Integritätsprüfung direkt nach dem Backup (pg_verifybackup, pgbackrest check). Zweitens: Archiv-Monitoring über pg_stat_archiver mit Alarm bei Lücken. Drittens: Restore-Drills in einer isolierten Umgebung.
Für den Restore-Drill hat sich ein wöchentlicher Automatismus bewährt: Ein Cronjob spielt das letzte Full-Backup in einen Container-Cluster ein, führt SELECT count(*) FROM orders; und drei bis fünf fachliche Konsistenzabfragen aus und schickt das Ergebnis an Slack oder E-Mail. Bei Abweichung eskaliert der Job. Die Kosten dafür sind minimal – ein Container mit 8 GB RAM und 100 GB Volume liegt bei Hetzner bei rund 12 € pro Monat.
Wichtige Kennzahlen für dein Monitoring-Dashboard:
Backup-Speicher ist 2026 günstig, aber die Unterschiede sind erheblich. Für 1 TB Backup-Daten pro Monat zahlst du je nach Anbieter:
| Anbieter | Preis pro TB/Monat | Egress | Eignung |
|---|---|---|---|
| Hetzner Storage Box BX11 | 3,81 € | unbegrenzt (Fair Use) | Self-Hosted, EU |
| Backblaze B2 | ~5,60 € | gratis bis 3× Speicher | S3-kompatibel |
| Wasabi | ~6,50 € | gratis | PITR-Repos |
| AWS S3 Standard | ~21 € | 0,09 $/GB | Enterprise |
| AWS S3 Glacier IR | ~3,70 € | Restore-Gebühren | Langzeitarchiv |
Bei Managed-PostgreSQL-Diensten sind Backups meist inklusive, aber mit engen Grenzen. IONOS Managed PostgreSQL startet bei rund 12 € pro Monat für kleine Instanzen, AWS RDS db.t4g.medium kostet etwa 0,068 USD pro Stunde plus 0,115 USD pro GB-Monat Speicher – bei 500 GB Backup-Volumen sind das schnell 60 USD extra pro Monat. Neon und Supabase bieten PITR in den Pro-Tarifen ab 25 USD bzw. 25 USD pro Monat, allerdings mit begrenzten Aufbewahrungsfenstern (7 bis 30 Tage).
Sicherheit ist der zweite Kostenblock. Drei Regeln sind nicht verhandelbar. Erstens: Backups verschlüsseln – pgBackRest mit repo1-cipher-type=aes-256-cbc oder clientseitige Verschlüsselung via age vor dem Upload. Zweitens: Credentials trennen – der Backup-User hat pg_read_all_data und REPLICATION, aber keine Schreibrechte. Drittens: Offline-Kopie – mindestens ein Backup-Generation pro Monat auf einem Medium, das nicht am Netz hängt (Band, externe Platte, Immutable Bucket mit Object Lock).
Gegen Ransomware hilft vor allem Object Lock mit Compliance-Modus. Ein Backup, das 30 Tage nicht gelöscht werden kann – auch nicht vom Root-Account – ist der einzige verlässliche Schutz gegen einen Angreifer mit Admin-Zugang. Rechne mit 10 bis 15 % Aufpreis bei den meisten Anbietern, aber es ist die günstigste Versicherung, die du abschließen kannst.
Für Datenbanken unter 20 GB ist ein täglicher pg_dump im Custom-Format mit --compress=zstd:3 völlig ausreichend. Ab 50 GB solltest du auf physische Backups mit pg_basebackup oder pgBackRest wechseln und pg_dump nur noch wöchentlich für logische Konsistenzprüfungen und Migrationssicherheit einsetzen. Der Grund ist die Laufzeit: Ein 500-GB-pg_dump blockiert Ressourcen über Stunden, während ein inkrementelles Basisbackup in Minuten durchläuft.
pg_dump erzeugt ein logisches Backup: SQL- oder Archivdateien mit Daten und Schema, die sich in jede PostgreSQL-Version einspielen lassen. pg_basebackup kopiert den physischen Cluster auf Dateiebene und benötigt exakt dieselbe Major-Version zum Wiederherstellen. Nur physische Backups lassen sich mit WAL-Archivierung zu Point-in-Time-Recovery kombinieren. Für Versionsmigrationen ist pg_dump die richtige Wahl, für RPO unter 5 Minuten das physische Backup.
Baue einen automatisierten Drill: Container starten, letztes Full-Backup entpacken, recovery.signal setzen, WAL-Archiv einbinden, Cluster starten und auf einen Zeitpunkt 30 Minuten vor dem letzten Backup zurücksetzen. Danach drei fachliche Konsistenzabfragen ausführen und die Ergebnisse mit der Produktion vergleichen. Läuft dieser Drill wöchentlich durch, hast du belastbare Sicherheit. Läuft er nicht durch, hast du ein Problem gefunden, bevor es dich findet.
Rechne mit 5 bis 25 GB WAL pro Tag, abhängig von Schreiblast und wal_compression. Bei einer Datenbank mit 2000 TPS sind 15 GB pro Tag realistisch. Für ein 30-Tage-Aufbewahrungsfenster brauchst du also rund 450 GB, mit zstd-Kompression etwa 250 GB. Wichtig: WAL-Segmente, die älter sind als dein ältestes Basisbackup, kannst du löschen – sie sind für PITR wertlos. Automatisiere diese Bereinigung über die Retention-Policy deines Backup-Tools.
Bei pg_dump-Backups ja, solange die Zielversion gleich oder neuer ist. Ein Dump von PostgreSQL 15 lässt sich problemlos in 17 oder 18 einspielen. Umgekehrt funktioniert es nicht. Bei physischen Backups gilt das Gegenteil: Sie sind strikt an die Major-Version gebunden. Ein Cluster-Backup von 16 lässt sich nicht in 17 starten – dafür brauchst du pg_upgrade oder eine logische Migration über pg_dumpall.