Iptables nach Neustart wiederherstellen
Nach einem Neustart ist der iptables-Regelsatz leer, weil der Kernel ihn nur im Arbeitsspeicher hält. Dieser Artikel zeigt drei Wege, ihn dauerhaft zu machen: das Paket iptables-persistent, eine eigene systemd-Unit und das ifupdown-Skript in /etc/network/if-pre-up.d/. Dazu die Grenzen jeder Variante auf Debian 13 und aktuellen Ubuntu-Versionen, und warum IPv6 dabei regelmäßig vergessen wird.
Warum iptables-Regeln nach einem Neustart verschwinden
iptables ist keine Konfigurationsdatei, sondern ein Zustand im Kernel. Die Regeln stehen in den Netfilter-Tabellen des laufenden Systems. Beim Herunterfahren sind sie weg. Nach dem Neustart beginnt die Filterkette wieder leer, auf Debian und Ubuntu in aller Regel mit der Policy ACCEPT — das System nimmt also alles an, bis jemand die Regeln zurückschreibt. Diesen Schritt erledigt keine der iptables-Komponenten von selbst, er muss beim Booten angestoßen werden.
Seit Debian 10 „Buster“ ist iptables dabei nur noch die Bedienoberfläche; darunter arbeitet das nf_tables-Subsystem des Kernels, ausgewählt über update-alternatives (Release Notes zu Debian 10). Ubuntu hat den Wechsel mit 20.10 nachgezogen (Ubuntu Security Documentation). Für das Speichern und Laden ändert das nichts: iptables-save und iptables-restore sprechen dasselbe Backend, das die Regeln vorher entgegengenommen hat. Welche Regeln überhaupt sinnvoll sind und warum die Wahl zwischen REJECT und DROP mehr als Geschmackssache ist, steht in iptables REJECT vs DROP.
Regeln sofort aus einer Datei laden
Wenn schon eine Regeldatei existiert, ist das Einspielen ein einziger Befehl. Angenommen, ein iptables-save hat die Regeln nach /etc/iptables/rules.v4 geschrieben:
sudo iptables-restore < /etc/iptables/rules.v4
Das ersetzt den kompletten Regelsatz sofort. iptables-restore leert die betroffenen Tabellen vorher, sofern du nicht --noflush angibst (iptables-restore(8)). Damit derselbe Aufruf nach jedem Neustart passiert, braucht es einen der drei Wege weiter unten.
Drei Wege, die Regeln über den Neustart zu bringen
Die drei gängigen Wege unterscheiden sich weniger im Komfort als darin, worauf sie sich verlassen: Methode 1 auf ifupdown, Methode 2 auf ein Debian-Paket, Methode 3 auf systemd. Wer sich nicht festlegen will, nimmt auf Debian oder Ubuntu Methode 2. Sie ist die kürzeste und die einzige, die IPv4 und IPv6 ohne Zusatzarbeit zusammen abdeckt.
1. Verwendung von iptables-save und iptables-restore
iptables-save schreibt den laufenden Regelsatz als Text auf die Standardausgabe, iptables-restore liest ihn zurück. Aus diesen zwei Befehlen baut man die Persistenz selbst. Ein Hinweis vorweg: Das Verzeichnis /etc/iptables/ legt erst das Paket iptables-persistent an. Ohne das Paket erzeugst du es mit sudo mkdir -p /etc/iptables, sonst scheitert die Umleitung im nächsten Schritt.
Schritt 1: Regeln speichern
Der folgende Befehl schreibt den laufenden IPv4-Regelsatz in eine Datei:
sudo iptables-save > /etc/iptables/rules.v4
Schritt 2: Skript zur Wiederherstellung anlegen
ifupdown führt vor dem Hochfahren einer Schnittstelle alles aus, was in /etc/network/if-pre-up.d/ liegt. Dort kommt das Skript hin:
sudo nano /etc/network/if-pre-up.d/iptables-restore
Inhalt der Datei:
#!/bin/sh
iptables-restore < /etc/iptables/rules.v4
exit 0
Schritt 3: Skript ausführbar machen
Ohne Ausführungsrecht überspringt ifupdown die Datei, ohne sich zu beschweren:
sudo chmod +x /etc/network/if-pre-up.d/iptables-restore
Diese Methode setzt voraus, dass das Netz wirklich von ifupdown verwaltet wird, also über /etc/network/interfaces. Auf einer Debian-Standardinstallation ist das der Fall. Auf Ubuntu nicht mehr: Seit 17.10 konfiguriert Netplan das Netz, und Netplan kennt keine Hook-Skripte. Die eigene FAQ verweist für diesen Zweck auf networkd-dispatcher (Netplan-FAQ, MigratingToNetplan). Dasselbe gilt für Desktops unter NetworkManager. Liegt das Skript an der richtigen Stelle und beim Booten passiert trotzdem nichts, ist das fast immer der Grund.
2. Verwendung des iptables-persistent Pakets
Auf Debian und Ubuntu nimmt ein Paket die Arbeit ab. iptables-persistent ist dabei nur der Plugin-Teil; die eigentliche Arbeit macht netfilter-persistent, ein Lader mit Plugin-Architektur, der die Regeln beim Booten einspielt und auf Kommando zurückschreibt (netfilter-persistent(8)). Das Paket legt /etc/iptables/ an und bringt je ein Plugin für IPv4 und IPv6 mit.
Installation des Pakets
Installation:
sudo apt install iptables-persistent
Die Installation fragt über debconf, ob die aktuell geladenen Regeln gesichert werden sollen. Ein „Ja“ schreibt sie nach /etc/iptables/rules.v4 und /etc/iptables/rules.v6.
Regeln aktualisieren
Spätere Änderungen sichert ein Befehl. Er überschreibt beide Dateien mit dem, was gerade im Kernel steht:
sudo netfilter-persistent save
Beim Booten startet netfilter-persistent.service und spielt die Dateien ein. Zwei Eigenheiten lohnen sich zu kennen. Das Plugin legt die Regeldatei mit Modus 0640 an, sie ist also nicht für jeden lesbar. Und netfilter-persistent stop löscht die Regeln nicht, sondern weist darauf hin, dass dafür flush zuständig ist. Das ist Absicht: Sonst stünde der Rechner während eines Paket-Upgrades ohne Firewall da. Wer es anders braucht, setzt FLUSH_ON_STOP in /etc/default/netfilter-persistent.
3. Verwendung von systemd-Diensten
Ohne Paket geht es mit einer eigenen Unit. Der Reiz ist begrenzt, denn man baut damit im Wesentlichen nach, was netfilter-persistent.service schon mitbringt. Sinnvoll ist es in schlanken Images, in die kein zusätzliches Paket soll, oder wenn die Regeln aus einer anderen Datei kommen als rules.v4.
Schritt 1: Dienst-Datei erstellen
Unit-Datei anlegen:
sudo nano /etc/systemd/system/iptables-restore.service
Inhalt:
[Unit]
Description=Restore iptables firewall rules
DefaultDependencies=no
Wants=network-pre.target
Before=network-pre.target shutdown.target
After=local-fs.target
Conflicts=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/iptables-restore /etc/iptables/rules.v4
[Install]
WantedBy=multi-user.target
Wants=network-pre.target ist die Zeile, die in den meisten Anleitungen fehlt. network-pre.target ist ein passives Ziel: Die Netzwerkdienste ordnen sich dahinter ein, ziehen es aber nicht selbst herein. Wer nur Before= schreibt und das Ziel nicht über Wants= aktiviert, bekommt keine wirksame Reihenfolge; die Unit läuft dann irgendwann, unter Umständen erst nach dem ersten Paket (systemd.special(7)). DefaultDependencies=no verhindert zusätzlich, dass systemd die Unit automatisch hinter basic.target einsortiert. Genau diese Kombination benutzen auch netfilter-persistent.service und nftables.service aus den Debian-Paketen.
Schritt 2: Dienst aktivieren
Dienst aktivieren:
sudo systemctl daemon-reload
sudo systemctl enable iptables-restore.service
Ob systemd die Unit so einsortiert, wie du es meinst, zeigt systemctl show -p Wants -p Before -p After iptables-restore.service. Die Syntax prüft systemd-analyze verify /etc/systemd/system/iptables-restore.service, und zwar besser vor dem Neustart als danach.
Regelsätze testen, bevor sie dich aussperren
Ein fehlerhafter Regelsatz, über SSH eingespielt, kostet im schlechtesten Fall den Zugang zum Server. iptables-restore hat dafür --test: Der Regelsatz wird geparst und aufgebaut, aber nicht übernommen.
sudo iptables-restore --test < /etc/iptables/rules.v4
netfilter-persistent macht das bei jedem Start von selbst. In der mitgelieferten /etc/default/netfilter-persistent stehen IPTABLES_TEST_RULESET=yes und IP6TABLES_TEST_RULESET=yes bereits aktiv. Scheitert der Testlauf, meldet das Plugin „Error: IPv4 rules failed test load. New rules NOT loaded“ und lässt die vorhandenen Regeln in Ruhe.
Der zweite Punkt, den viele Anleitungen unterschlagen: iptables-save sichert ausschließlich IPv4. Ein Server mit IPv6-Adresse bleibt auf dem zweiten Stack ungefiltert, auch wenn die v4-Regeln sauber stehen. Die Gegenstücke heißen ip6tables-save und ip6tables-restore, die Datei /etc/iptables/rules.v6.
sudo ip6tables-save > /etc/iptables/rules.v6
Und eine Selbstverständlichkeit, die oft ausbleibt: einmal kontrolliert neu starten und danach sudo iptables -L -n -v mit dem Stand von vorher vergleichen. Welche Dienste überhaupt nach außen lauschen, zeigt Genutzte Ports in Linux anzeigen.
Fehlerbehebung und häufige Probleme
Wenn nach dem Neustart keine oder die falschen Regeln stehen, sind meist diese drei Ursachen im Spiel.
Problem: Regeln werden nicht geladen
Der erste Blick gehört dem Dienst: systemctl status netfilter-persistent beziehungsweise systemctl status iptables-restore.service, dazu journalctl -u netfilter-persistent -b für den letzten Bootvorgang. Fehlt die Regeldatei, meldet das Plugin „Warning: skipping IPv4 (no rules to load)“ und bricht nicht ab. Der Dienst gilt dann als erfolgreich gelaufen, obwohl keine einzige Regel geladen wurde. Beim eigenen Skript in /etc/network/if-pre-up.d/ ist die häufigste Ursache das fehlende Ausführungsrecht, die zweithäufigste, dass ifupdown gar nicht im Spiel ist.
Problem: Konflikte mit anderen Diensten
Docker, libvirt, ufw und fail2ban schreiben eigene Ketten. Docker legt in der filter-Tabelle unter anderem DOCKER, DOCKER-USER und DOCKER-FORWARD an, in der nat-Tabelle eine weitere DOCKER-Kette, und erwartet eigene Regeln ausdrücklich in DOCKER-USER (Docker-Dokumentation). Wer einen kompletten Regelsatz einspielt, während so ein Dienst läuft, löscht dessen Ketten mit: iptables-restore leert die Tabelle ohne --noflush vollständig. Entweder sicherst du erst, wenn alle Dienste hochgefahren sind, oder du lädst mit --noflush und beschränkst die Datei auf eigene Ketten.
Problem: Inkonsistente Regeln
Zwei Mechanismen, die beim Booten dieselbe Datei laden, sind kein doppeltes Netz, sondern eine Fehlerquelle: Wer zuletzt läuft, bestimmt den Regelsatz. Nach der Installation von iptables-persistent gehört das Skript aus /etc/network/if-pre-up.d/ also weg und die eigene Unit deaktiviert. Dazu ein leiserer Fall: iptables-legacy und iptables-nft führen getrennte Regelsätze. Was über das Legacy-Backend angelegt wurde, sieht iptables-save im nft-Modus nicht. Welche Variante aktiv ist, verrät update-alternatives --display iptables.
Oder gleich nftables nehmen
Unter iptables läuft auf Debian 13 und aktuellen Ubuntu-Versionen ohnehin nf_tables. Wer keine bestehenden iptables-Regeln pflegen muss, kann den Umweg auslassen. nft list ruleset gibt den Regelsatz aus, /etc/nftables.conf ist die Datei, die nftables.service beim Booten einliest. Persistenz ist dort kein Zusatzpaket, sondern eingebaut.
Umgekehrt gilt: die beiden Welten nicht auf demselben Rechner mischen. Ein nftables.service, der seine Datei lädt, und ein netfilter-persistent, der danach seine eigene einspielt, ergeben einen Zustand, den keiner der beiden Regelsätze allein beschreibt. Die mitgelieferte /etc/nftables.conf beginnt mit flush ruleset und räumt damit auch ab, was iptables vorher angelegt hat.
Fazit
Für Debian und Ubuntu ist die Antwort kurz: iptables-persistent installieren, Änderungen mit netfilter-persistent save sichern, fertig, IPv6 inklusive. Die eigene systemd-Unit lohnt sich, wenn kein zusätzliches Paket ins System soll. Das ifupdown-Skript nur dort, wo das Netz noch aus /etc/network/interfaces kommt. Was in allen drei Fällen bleibt, ist der kontrollierte Neustart hinterher. Ein Regelsatz, von dem du nur annimmst, dass er nach dem Boot steht, ist keiner.