Linux-Firewall: iptables und nftables im Vergleich
iptables vs. nftables im Detail: Ketten, Tabellen, conntrack, NAT, ufw/firewalld als Frontends und wie du Regeln im KMU-Betrieb persistent machst.
Warum das Thema mehr ist als „Firewall an, Firewall aus”
Jede moderne Linux-Distribution bringt einen Paketfilter im Kernel mit: Netfilter. Das ist das Framework, das Pakete auf ihrem Weg durch den Kernel abfangen, filtern, verändern (NAT) oder verwerfen kann. Die Frage ist nur, mit welchem Werkzeug du mit Netfilter sprichst – und genau hier beginnt die Verwirrung, die dir in jedem Schweizer KMU früher oder später begegnet: Der alte Server läuft noch mit klassischem iptables, der neue Debian-Host nutzt nftables, und auf der Workstation regelt ufw alles im Hintergrund. Wer nicht versteht, wie diese Ebenen zusammenhängen, verliert beim Troubleshooting schnell den Überblick – vor allem, wenn ein Kunde anruft, weil eine Anwendung plötzlich keine Verbindung mehr aufbaut.
Dieser Artikel zeigt dir die Architektur unter der Haube, den echten Unterschied zwischen iptables und nftables, wie NAT und Port-Forwarding funktionieren, was conntrack mit Stateful Filtering zu tun hat, und wie du Regeln über einen Reboot hinweg persistent machst.
Netfilter, iptables und nftables: Wer macht was?
Ein häufiges Missverständnis: iptables und nftables sind keine Firewalls im Kernel – sie sind Userspace-Werkzeuge, die Regeln in Netfilter-Strukturen im Kernel schreiben. Netfilter selbst ist seit Kernel 2.4 (Jahr 2001) fester Bestandteil des Linux-Kernels und stellt Hook-Punkte bereit, an denen Pakete abgefangen werden können.
- iptables (seit 1998/2001) nutzt die klassischen Netfilter-Hooks direkt und verwaltet Regeln in vier bis fünf Tabellen (
filter,nat,mangle,raw,security) mit fest vordefinierten Ketten. - nftables (seit Kernel 3.13, 2014) ist der offizielle Nachfolger. Es nutzt eine eigene, generischere Kernel-Schnittstelle (
nf_tables) mit einer internen virtuellen Maschine, die kompilierten Bytecode ausführt. Tabellen und Ketten sind hier nicht mehr fest vorgegeben, sondern werden vom Administrator selbst definiert. - iptables-nft: Seit Debian 10 (Buster) und den meisten aktuellen Distributionen ist der klassische
iptables-Befehl nur noch eine Kompatibilitätsschicht, die deine Regeln in nftables-Syntax übersetzt. Der eigentliche Kernel-Regelsatz liegt also längst in nftables – du tippst nur noch die alte Syntax ein.
iptables-Ketten im Detail: INPUT, OUTPUT, FORWARD
Auch wenn du künftig eher nftables schreiben wirst, musst du das klassische Kettenmodell verstehen – es taucht in jeder Doku, jedem Legacy-Server und jeder Zertifizierung auf.
Die filter-Tabelle (Standardtabelle für reines Filtern) hat drei Standardketten:
| Kette | Wann greift sie | Typischer Einsatz |
|---|---|---|
INPUT | Pakete mit Ziel = dieser Host | SSH, HTTP, DB-Zugriff auf den Server selbst einschränken |
OUTPUT | Pakete, die dieser Host selbst erzeugt | Ausgehenden Traffic kontrollieren (z. B. nur bestimmte Ziel-IPs erlauben) |
FORWARD | Pakete, die durch den Host hindurch geroutet werden | Der Host als Router/Gateway zwischen zwei Netzen |
Dazu kommen weitere Tabellen mit eigenen Ketten: nat (mit PREROUTING, POSTROUTING, INPUT, OUTPUT) für Adressübersetzung, mangle für das Modifizieren von Paket-Metadaten (TTL, TOS/DSCP) und raw zum Ausklinken aus dem Connection-Tracking.
Ein typisches, restriktives iptables-Regelwerk für einen Server sieht so aus:
# Alles verwerfen, was nicht explizit erlaubt ist
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Loopback immer erlauben (essenziell fuer lokale Dienste)
iptables -A INPUT -i lo -j ACCEPT
# Bestehende Verbindungen durchlassen (siehe conntrack weiter unten)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# SSH nur von internem Management-Netz
iptables -A INPUT -p tcp -s 10.10.5.0/24 --dport 22 -j ACCEPT
# HTTPS fuer alle
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# ICMP (Ping) fuer Diagnose zulassen
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# Rest verwerfen und loggen
iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROP: " --log-level 4
iptables -A INPUT -j DROP
nftables: Architektur und Syntax
nftables kehrt das Prinzip um: Es gibt keine vordefinierten Tabellen oder Ketten. Du legst alles selbst an, was Übersicht schafft, aber am Anfang ungewohnt ist. Dafür bekommst du eine einheitliche Syntax für IPv4, IPv6, ARP und Bridging-Traffic (über die Adressfamilie inet), statt vier getrennter Tools (iptables, ip6tables, arptables, ebtables).
Grundstruktur: Tabelle → Kette → Regel
# Tabelle anlegen (Adressfamilie inet = IPv4 + IPv6 gemeinsam)
nft add table inet filter
# Basis-Kette fuer eingehenden Traffic anlegen
# hook input = Netfilter-Hook, priority 0 = Standardprioritaet, policy drop = Default-Politik
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
# Regeln hinzufuegen
nft add rule inet filter input iif lo accept
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport 22 ip saddr 10.10.5.0/24 accept
nft add rule inet filter input tcp dport 443 accept
nft add rule inet filter input icmp type echo-request accept
nft add rule inet filter input log prefix "NFT-DROP: " drop
Der produktive Weg ist aber nicht die interaktive Eingabe einzelner Befehle, sondern eine deklarative Konfigurationsdatei unter /etc/nftables.conf:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
ct state invalid drop
tcp dport 22 ip saddr 10.10.5.0/24 accept
tcp dport { 80, 443 } accept
icmp type echo-request accept
log prefix "NFT-DROP: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Aktivieren mit nft -f /etc/nftables.conf und prüfen mit nft list ruleset.
iptables vs. nftables: Die Entscheidungstabelle
| Kriterium | iptables (legacy) | nftables |
|---|---|---|
| Kernel-Schnittstelle | Direkter Netfilter-Zugriff, pro Protokollfamilie eigenes Binary | Einheitliche nf_tables-API, ein Binary (nft) fuer alle Familien |
| Performance bei vielen Regeln | Linear (jede Regel wird sequenziell geprueft) | Bytecode-VM, Sets/Maps mit Hash-Lookup – deutlich schneller bei grossen Regelsaetzen |
| Syntax | Historisch gewachsen, viele Spezialfaelle | Konsistenter, deklarativ, aber neue Lernkurve |
| IPv4/IPv6 gemeinsam verwalten | Nein (getrennte Tools iptables/ip6tables) | Ja, ueber Adressfamilie inet |
| Atomare Regel-Updates | Nur mit iptables-restore | Nativ mit nft -f (ganze Ruleset-Datei atomar geladen) |
| Verfuegbarkeit auf aktuellen Distros | Ueber Kompatibilitaetsschicht (iptables-nft) | Nativ seit Debian 10, RHEL 8, Ubuntu 20.04 |
| Doku/Community-Beispiele im Netz | Riesig, jahrzehntealt | Wachsend, aber noch nicht so umfassend |
| Empfehlung fuer Neuprojekte | Nein, nur bei Legacy-Zwang | Ja |
Frontends: ufw und firewalld
Weder rohes iptables noch rohes nftables sind im Alltag besonders komfortabel. Deshalb setzen die meisten Distributionen auf ein Frontend, das die Regeln im Hintergrund generiert.
ufw (Uncomplicated Firewall) – Ubuntu/Debian-Welt
ufw ist bewusst simpel gehalten und für Server mit überschaubarem Regelwerk gedacht.
# Status und aktivieren
sudo ufw status verbose
sudo ufw enable
# Grundregeln
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Dienste erlauben (nutzt /etc/services fuer Namen)
sudo ufw allow ssh
sudo ufw allow 443/tcp
sudo ufw allow from 10.10.5.0/24 to any port 22
# Regel mit Kommentar (hilft bei der Doku!)
sudo ufw allow 3389/tcp comment 'RDP fuer Terminalserver'
# Regel loeschen
sudo ufw status numbered
sudo ufw delete 3
# Anwendungsprofile (definiert in /etc/ufw/applications.d/)
sudo ufw app list
sudo ufw allow 'Nginx Full'
ufw arbeitet standardmässig auf Basis von iptables (bzw. iptables-nft), es gibt aber auch einen nftables-Backend-Modus (/etc/ufw/ufw.conf → IPT_SYSCTL/Backend-Auswahl je nach Version).
firewalld – RHEL/CentOS/Fedora/SUSE-Welt
firewalld denkt in Zonen statt in linearen Regeln – ein Konzept, das für Laptops mit wechselnden Netzen (Büro, Heimnetz, öffentliches WLAN) entwickelt wurde, sich aber auch für Server mit mehreren Interfaces (LAN, DMZ, Management) eignet.
# Aktive Zone eines Interfaces anzeigen
firewall-cmd --get-active-zones
# Interface einer Zone zuweisen
sudo firewall-cmd --zone=internal --change-interface=eth1 --permanent
# Dienst dauerhaft in einer Zone erlauben
sudo firewall-cmd --zone=public --add-service=https --permanent
sudo firewall-cmd --zone=internal --add-port=3306/tcp --permanent
# Aenderungen aktivieren (ohne Neustart)
sudo firewall-cmd --reload
# Rich Rules fuer komplexere Faelle (z.B. Quell-IP + Zeitfenster)
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.10" service name="ssh" accept' --permanent
# Aktuelle Konfiguration einer Zone anzeigen
firewall-cmd --zone=public --list-all
firewalld nutzt seit Version 0.6+ nftables als Standard-Backend (früher iptables-direct). Das kannst du in /etc/firewalld/firewalld.conf über FirewallBackend=nftables prüfen bzw. umstellen.
Stateful Filtering: Wie conntrack funktioniert
Der grösste konzeptionelle Sprung gegenüber einfachen Paketfiltern ist Connection Tracking (conntrack). Ohne conntrack müsstest du für jede TCP-Verbindung sowohl die ausgehende Anfrage als auch die zugehörige Antwort explizit erlauben – bei dynamischen Portbereichen (Ephemeral Ports, meist 32768–60999) praktisch unmöglich sauber zu pflegen.
conntrack führt eine Tabelle aller aktiven Verbindungen im Kernel und ordnet jedes Paket einem von vier Zuständen zu:
| Zustand | Bedeutung |
|---|---|
NEW | Erstes Paket einer neuen Verbindung (z. B. TCP SYN) |
ESTABLISHED | Teil einer bereits bestätigten Verbindung (Antwortverkehr) |
RELATED | Gehört logisch zu einer bestehenden Verbindung, ist aber technisch eine neue (z. B. FTP-Datenkanal, ICMP-Fehlermeldung zu einer TCP-Session) |
INVALID | Passt zu keiner bekannten Verbindung – meist ein Hinweis auf fehlerhafte oder manipulierte Pakete |
Damit reicht eine einzige Regel, um den gesamten Rückverkehr für bereits erlaubte Verbindungen freizugeben:
# iptables
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# nftables
nft add rule inet filter input ct state established,related accept
Die conntrack-Tabelle selbst kannst du live einsehen und analysieren – extrem nützlich beim Troubleshooting von NAT- oder Timeout-Problemen:
# conntrack-Tool installieren (meist im Paket conntrack)
sudo apt install conntrack
# Aktive Verbindungen anzeigen
sudo conntrack -L
# Live mitverfolgen
sudo conntrack -E
# Groesse und Auslastung der Tabelle
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
NAT und Port-Forwarding
NAT (Network Address Translation) findet in einer eigenen Tabelle statt, die früh (PREROUTING) bzw. spät (POSTROUTING) im Paketweg ansetzt.
Klassisches Masquerading (Internet-Gateway für ein LAN)
# iptables
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.10.0/24 -j MASQUERADE
# nftables
nft add table ip nat
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip nat postrouting oif eth0 ip saddr 192.168.10.0/24 masquerade
MASQUERADE eignet sich für dynamische WAN-IPs (DHCP/PPPoE). Hast du eine statische öffentliche IP, ist SNAT (Source NAT) die etwas performantere und explizitere Variante, weil der Kernel die IP nicht bei jedem Paket neu ermitteln muss:
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.10.0/24 -j SNAT --to-source 203.0.113.5
Port-Forwarding (DNAT) – Beispiel: Interner RDP-Server von aussen erreichbar
# iptables: Eingehende Pakete auf Port 33890 an internen Host umleiten
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 33890 -j DNAT --to-destination 192.168.10.50:3389
# Passende FORWARD-Regel nicht vergessen!
iptables -A FORWARD -p tcp -d 192.168.10.50 --dport 3389 -j ACCEPT
# nftables-Aequivalent
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add rule ip nat prerouting iif eth0 tcp dport 33890 dnat to 192.168.10.50:3389
nft add rule inet filter forward ip daddr 192.168.10.50 tcp dport 3389 accept
Entscheidungsablauf für ein typisches Gateway-Setup
- IP-Forwarding aktivieren – ohne das leitet der Kernel gar nichts weiter:
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf sudo sysctl -p - NAT-Regel definieren (MASQUERADE für dynamische WAN-IP, SNAT für statische).
- FORWARD-Policy auf DROP setzen und nur explizit benötigte Ziele/Ports freigeben.
- conntrack-Regel für Rückverkehr in FORWARD nicht vergessen (
ct state established,related accept). - Testen von aussen – idealerweise über einen externen Scan (z. B. von einem Mobilfunknetz aus), nicht nur aus dem eigenen LAN, weil Hairpin-NAT sich anders verhält.
Regeln persistent machen
Sowohl iptables- als auch nftables-Regeln leben standardmässig nur im Kernel-Speicher – nach einem Reboot sind sie weg, wenn du nicht für Persistenz sorgst.
iptables persistent (Debian/Ubuntu)
sudo apt install iptables-persistent
# Aktuelle Regeln sichern
sudo netfilter-persistent save
# Entspricht: iptables-save > /etc/iptables/rules.v4
# ip6tables-save > /etc/iptables/rules.v6
# Manuelles Backup/Restore
sudo iptables-save > /etc/iptables/rules.v4
sudo iptables-restore < /etc/iptables/rules.v4
iptables persistent (RHEL/CentOS)
sudo dnf install iptables-services
sudo systemctl enable iptables
sudo service iptables save
nftables persistent
nftables hat Persistenz von Haus aus eingebaut, weil die Konfiguration ohnehin als Datei vorliegt:
# Systemd-Service ist meist schon vorhanden
sudo systemctl enable nftables
# Konfiguration liegt unter /etc/nftables.conf (Debian) bzw.
# /etc/sysconfig/nftables.conf (RHEL)
sudo nft list ruleset > /etc/nftables.conf
sudo systemctl restart nftables
ufw / firewalld
Beide Frontends kümmern sich selbst um Persistenz – ufw schreibt nach /etc/ufw/, firewalld nach /etc/firewalld/. Solange du mit den jeweiligen CLI-Befehlen arbeitest (und bei firewalld --permanent nicht vergisst), überlebt die Konfiguration Reboots automatisch.
Troubleshooting-Checkliste
Wenn eine Verbindung blockiert wird und du nicht weisst warum:
# 1. Welches Backend laeuft ueberhaupt?
iptables --version
nft --version
# 2. Aktuelles Regelwerk mit Zaehlern anzeigen (zeigt welche Regel matcht)
iptables -L -v -n --line-numbers
nft list ruleset -a
# 3. Live mitschneiden, was ankommt
tcpdump -i eth0 port 443 -nn
# 4. Kernel-Logs pruefen (bei LOG-Regeln)
journalctl -k -f | grep DROP
# 5. conntrack-Status der betroffenen Verbindung
conntrack -L | grep 192.168.10.50
Fehlt dir Netzwerkwissen für die Interpretation der Paketmitschnitte, hilft Wireshark – Grundlagen der Paketanalyse als Ergänzung zu tcpdump.
Weiterlernen
- nftables Wiki – offizielle Projekt-Dokumentation
- Debian Wiki: nftables
- Red Hat: Getting started with nftables (RHEL)
- firewalld Dokumentation (firewalld.org)
- Ubuntu Server Guide: UFW (Uncomplicated Firewall)
- Netfilter/conntrack-tools Projektseite
Videos
Kommentare
Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.
- Lade Kommentare …