Introductie: Waarom nftables essentieel is in 2026
Als je een Linux-server beheert die aan het internet hangt, dan weet je het eigenlijk al: een goed geconfigureerde firewall is geen luxe maar pure noodzaak. De cijfers uit 2025 liegen er niet om — 89% van alle aanvallen op Linux-endpoints zijn brute-force pogingen, webshells vormen met 49,6% het meest voorkomende type Linux-malware, en het Linux-kernel ontving maar liefst 5.530 CVE-meldingen in 2025. Dat is een stijging van 28% ten opzichte van het jaar daarvoor. Geautomatiseerde botnets zoals P2PInfect (verantwoordelijk voor meer dan 80% van SSH-aanvallen in Q4 2025) en Tsunami scannen het internet op industriële schaal, op zoek naar slecht beveiligde servers.
In dit landschap is nftables niet langer "de opvolger van iptables die er ooit aankomt" — het ís de standaard. Alle grote distributies gebruiken nftables nu als standaard firewall-framework: RHEL 8+, Debian 10+ en Ubuntu 20.04+ zijn volledig overgestapt. Het klassieke iptables is officieel deprecated en wordt alleen nog onderhouden via de iptables-nft compatibiliteitslaag. De nieuwste versie is nftables 1.1.6, uitgebracht in december 2025, met verbeterde ondersteuning voor lightweight tunnel templates (vxlan, geneve, erspan), Big Endian fixes en uitgebreide JSON-ondersteuning.
In deze gids neem ik je stap voor stap mee door alles wat je moet weten over nftables firewall hardening — van de basis tot geavanceerde configuraties met dynamische sets, Fail2Ban-integratie en geo-blocking. Alle voorbeelden zijn getest en productieklaar voor 2026.
Waarom nftables in plaats van iptables?
Als je al jaren met iptables werkt, dan snap ik de aarzeling. Waarom zou je overstappen naar iets nieuws als het oude prima draait? Het korte antwoord: nftables is sneller, eenvoudiger en krachtiger. Maar laten we dat concreet maken.
Vergelijking: nftables vs. iptables
- Unified CLI — iptables had aparte commando's voor IPv4 (
iptables), IPv6 (ip6tables), ARP (arptables) en bridging (ebtables). nftables gebruikt één enkel commando:nft. Dat scheelt enorm. - inet-familie — Met de
inet-familie schrijf je één set regels voor zowel IPv4 als IPv6 tegelijk. Geen dubbel onderhoud meer. - Geen standaard tabellen of chains — iptables had altijd voorgedefinieerde chains (INPUT, OUTPUT, FORWARD). Bij nftables begin je met een schone lei en bouw je precies wat je nodig hebt.
- O(1) performance via sets en maps — Waar iptables elke regel lineair doorloopt (O(n)), gebruikt nftables hash-gebaseerde sets en verdict maps voor constant-time lookups. Bij honderden of duizenden regels maakt dit een enorm verschil.
- Atomaire regelupdates — nftables laadt de volledige ruleset atomair. Er is geen moment waarop je firewall "half geladen" is, wat bij iptables-restore wel kon voorkomen bij fouten halverwege.
- Ingebouwde sets — Waar je bij iptables het externe pakket
ipsetnodig had voor IP-lijsten, heeft nftables sets, named maps en concatenated ranges native ingebouwd. - Compatibiliteitslaag — De
iptables-nfttool vertaalt iptables-commando's naar nftables-regels achter de schermen. Zo kun je geleidelijk migreren zonder bestaande scripts direct te breken.
Eerlijk gezegd, sinds ik volledig op nftables ben overgestapt, is het beheren van firewallregels op servers met gemengd IPv4/IPv6-verkeer dramatisch eenvoudiger geworden. Eén configuratiebestand, één syntax, geen verrassingen. Ik zou niet meer terug willen.
Installatie en eerste configuratie
Installatie per distributie
Op de meeste moderne distributies is nftables al geïnstalleerd. Zo niet, dan is het snel geregeld:
# Debian / Ubuntu
sudo apt update && sudo apt install nftables
# RHEL / Fedora / AlmaLinux
sudo dnf install nftables
# Arch Linux
sudo pacman -S nftables
Systemd-service inschakelen
Na installatie moet je de nftables-service inschakelen zodat je regels automatisch worden geladen bij het opstarten:
# Service inschakelen en starten
sudo systemctl enable nftables
sudo systemctl start nftables
# Controleer de status
sudo systemctl status nftables
Versie controleren
# Controleer de geïnstalleerde versie
nft --version
# Verwachte output: nftables v1.1.6 (Lester Gooch)
Bestandsstructuur
Het hoofdconfiguratiebestand bevindt zich standaard op /etc/nftables.conf. Je kunt aanvullende configuratiebestanden opnemen via de include-directive:
#!/usr/sbin/nft -f
# Wis bestaande ruleset
flush ruleset
# Inclusie van aanvullende configuratiebestanden
include "/etc/nftables.d/*.nft"
# Hoofdconfiguratie volgt hieronder
table inet filter {
# ...
}
Het is een goede gewoonte om een map /etc/nftables.d/ aan te maken voor modulaire configuratie. Zo kun je Fail2Ban, geo-blocking en applicatiespecifieke regels netjes gescheiden houden (en geloof me, dat ga je waarderen als je configuratie groeit).
De basisprincipes: tabellen, chains en regels
Om nftables effectief te gebruiken, moet je drie kernconcepten begrijpen: tabellen, chains en regels. Laten we ze stuk voor stuk doorlopen.
Tabellen en families
Een tabel is simpelweg een container voor chains en regels. Elke tabel hoort bij een adresfamilie:
- ip — Alleen IPv4-verkeer
- ip6 — Alleen IPv6-verkeer
- inet — Zowel IPv4 als IPv6 (aanbevolen voor de meeste servers)
- arp — ARP-verkeer
- bridge — Bridging-verkeer
- netdev — Verwerking op het allerlaagste niveau, direct bij de netwerkinterface (ideaal voor DDoS-mitigatie en geo-blocking)
# Een tabel aanmaken voor IPv4 en IPv6 gecombineerd
nft add table inet mijn_firewall
# Een tabel aanmaken specifiek voor netdev (vroege filtering)
nft add table netdev vroege_filter
Chains: base chains en reguliere chains
Een base chain is gekoppeld aan een netfilter-hook en bepaalt wanneer in de pakketverwerking de regels worden toegepast. De beschikbare hooks zijn:
- input — Inkomend verkeer bestemd voor de server zelf
- output — Uitgaand verkeer vanaf de server
- forward — Verkeer dat door de server wordt doorgestuurd (routing)
- prerouting — Verkeer voordat routeringsbeslissingen worden genomen (NAT)
- postrouting — Verkeer na routeringsbeslissingen (masquerading)
Een reguliere chain heeft geen hook en wordt alleen aangeroepen via jump of goto vanuit andere chains — handig voor het organiseren van complexere regelsets.
# Base chain met hook en default policy
nft add chain inet mijn_firewall input \
'{ type filter hook input priority 0; policy drop; }'
# Reguliere chain (geen hook)
nft add chain inet mijn_firewall ssh_regels
Regels
Regels worden toegevoegd aan chains en bevatten match-expressies en een actie (verdict). Hier zijn een paar voorbeelden:
# Sta verkeer toe op de loopback-interface
nft add rule inet mijn_firewall input iif lo accept
# Sta bestaande en gerelateerde verbindingen toe
nft add rule inet mijn_firewall input ct state established,related accept
# Sta SSH toe op poort 22
nft add rule inet mijn_firewall input tcp dport 22 accept
# Drop al het overige verkeer (wordt al gedaan door policy drop)
nft add rule inet mijn_firewall input counter drop
Complete geharde serverconfiguratie
Oké, nu wordt het serieus. Hieronder vind je een volledige, productieklare /etc/nftables.conf die ik als basis gebruik voor alle servers die ik beheer. Deze configuratie implementeert een default-deny beleid met zorgvuldig geselecteerde uitzonderingen.
#!/usr/sbin/nft -f
# /etc/nftables.conf — Geharde serverconfiguratie 2026
# nftables 1.1.6+ | inet-familie (IPv4 + IPv6)
flush ruleset
# ========================
# Variabelen
# ========================
define SSH_PORT = 22
define HTTP_PORTS = { 80, 443 }
define DNS_SERVERS = { 1.1.1.1, 8.8.8.8, 9.9.9.9 }
define LAN_SUBNET = 10.0.0.0/8
define MONITOR_PORTS = { 9090, 9100 } # Prometheus, Node Exporter
# ========================
# Inclusie Fail2Ban
# ========================
include "/etc/nftables.d/*.nft"
# ========================
# Hoofdtabel
# ========================
table inet firewall {
# --- Dynamische set voor SSH brute-force bescherming ---
set ssh_ratelimit {
type ipv4_addr
flags dynamic,timeout
timeout 5m
}
set ssh_ratelimit6 {
type ipv6_addr
flags dynamic,timeout
timeout 5m
}
# --- INPUT chain ---
chain input {
type filter hook input priority 0; policy drop;
# Loopback-interface altijd toestaan
iif "lo" accept
# Connection tracking: bestaande en gerelateerde verbindingen
ct state established,related accept
# Ongeldige pakketten direct droppen
ct state invalid counter drop
# ICMP rate limiting (IPv4)
ip protocol icmp icmp type {
echo-request,
destination-unreachable,
time-exceeded
} limit rate 5/second burst 10 packets accept
# ICMPv6 essentieel verkeer toestaan (NDP, etc.)
ip6 nexthdr icmpv6 icmpv6 type {
echo-request,
echo-reply,
nd-neighbor-solicit,
nd-neighbor-advert,
nd-router-solicit,
nd-router-advert,
mld-listener-query,
destination-unreachable,
packet-too-big,
time-exceeded,
parameter-problem
} limit rate 10/second burst 20 packets accept
# SSH met per-IP rate limiting (IPv4)
tcp dport $SSH_PORT ip saddr \
@ssh_ratelimit ct state new \
add @ssh_ratelimit { ip saddr \
limit rate 4/minute burst 6 packets } accept
# SSH met per-IP rate limiting (IPv6)
tcp dport $SSH_PORT ip6 saddr \
@ssh_ratelimit6 ct state new \
add @ssh_ratelimit6 { ip6 saddr \
limit rate 4/minute burst 6 packets } accept
# SSH die rate limit overschrijdt — loggen en droppen
tcp dport $SSH_PORT ct state new \
log prefix "nft-ssh-denied: " \
counter drop
# Webverkeer (HTTP/HTTPS) toestaan
tcp dport $HTTP_PORTS accept
# Monitoringpoorten alleen vanuit LAN
ip saddr $LAN_SUBNET tcp dport $MONITOR_PORTS accept
# Alle overige gedropte pakketten loggen (rate limited)
limit rate 3/minute burst 5 packets \
log prefix "nft-input-dropped: " counter drop
# Stille drop voor de rest
counter drop
}
# --- FORWARD chain ---
chain forward {
type filter hook forward priority 0; policy drop;
# Alleen toestaan als deze server als router fungeert
# ct state established,related accept
# Standaard: alles droppen
counter drop
}
# --- OUTPUT chain ---
chain output {
type filter hook output priority 0; policy accept;
# Loopback toestaan
oif "lo" accept
# Bestaande verbindingen toestaan
ct state established,related accept
# DNS-uitgaand verkeer toestaan
ip daddr $DNS_SERVERS udp dport 53 accept
ip daddr $DNS_SERVERS tcp dport 53 accept
# HTTP/HTTPS-uitgaand (voor updates, API-calls)
tcp dport $HTTP_PORTS accept
# NTP-uitgaand
udp dport 123 accept
# Uitgaand SMTP (optioneel, voor mailnotificaties)
tcp dport { 25, 587 } accept
# Alles overige loggen (optioneel, voor debugging)
# log prefix "nft-output-dropped: " counter drop
}
}
Sla dit bestand op als /etc/nftables.conf en valideer de syntax voordat je het laadt. Dit is belangrijk — je wilt niet per ongeluk jezelf buitensluiten:
# Syntaxvalidatie zonder daadwerkelijk laden
sudo nft -c -f /etc/nftables.conf
# Laden van de configuratie
sudo systemctl reload nftables
# Controleer de actieve ruleset
sudo nft list ruleset
Geavanceerde brute-force bescherming met dynamische sets
Dit is wat mij betreft een van de meest indrukwekkende features van nftables: dynamische sets voor geautomatiseerde brute-force bescherming — zonder dat je externe tools als Fail2Ban nodig hebt. Laat me uitleggen hoe dit werkt.
Hoe dynamische sets werken
Een dynamische set is een set die tijdens runtime automatisch wordt gevuld op basis van verkeer. Met het add-statement en de limit rate-expressie kun je per IP-adres bijhouden hoeveel verbindingen er binnen een bepaald tijdvenster zijn gemaakt.
# Definitie van de dynamische set
set ssh_blocklist {
type ipv4_addr
flags dynamic,timeout
timeout 10m # Entries verlopen na 10 minuten
size 65536 # Maximaal 65536 entries
}
# De regel die de set vult en evalueert
tcp dport 22 ct state new \
add @ssh_blocklist { ip saddr \
limit rate over 4/minute burst 6 packets } \
log prefix "nft-ssh-bruteforce: " drop
Het sleutelwoord hier is limit rate over. In tegenstelling tot limit rate (dat verkeer toestaat tot aan de limiet), matcht limit rate over alleen wanneer de limiet wordt overschreden. Dus: de eerste 4 verbindingen per minuut worden doorgelaten, en elke poging daarna wordt gelogd en gedropt.
Een subtiel maar belangrijk verschil.
IPv6-variant met inet-familie
Omdat we de inet-familie gebruiken, moeten we aparte sets definiëren voor IPv4 en IPv6. Dat is een beetje jammer — concatenated types binnen sets ondersteunen nog geen gemengde adresfamilies — maar het is prima te doen:
table inet firewall {
set ssh_limit_v4 {
type ipv4_addr
flags dynamic,timeout
timeout 5m
}
set ssh_limit_v6 {
type ipv6_addr
flags dynamic,timeout
timeout 5m
}
chain input {
type filter hook input priority 0; policy drop;
# IPv4 SSH rate limiting
tcp dport 22 ip saddr @ssh_limit_v4 ct state new \
add @ssh_limit_v4 { ip saddr \
limit rate over 3/minute } drop
# IPv6 SSH rate limiting
tcp dport 22 ip6 saddr @ssh_limit_v6 ct state new \
add @ssh_limit_v6 { ip6 saddr \
limit rate over 3/minute } drop
# Normale SSH-verbindingen toestaan
tcp dport 22 ct state new accept
}
}
Voordelen ten opzichte van Fail2Ban
Dynamische sets werken volledig in de kernel, zonder userspace-processen die logbestanden moeten parsen. Dat betekent: lagere latency, minder CPU-gebruik en geen afhankelijkheid van logrotatie of journald.
Toch raad ik aan om dynamische sets te combineren met Fail2Ban. De nftables-aanpak vangt het eerste geweld op, terwijl Fail2Ban persistente aanvallers afhandelt met langere bans. Twee lagen zijn beter dan één.
Rate limiting en verbindingslimieten
SSH-bescherming is natuurlijk belangrijk, maar er zijn meer scenario's waarbij rate limiting cruciaal is. Laten we de belangrijkste technieken langslopen.
Per-IP rate limiting voor webverkeer
# Set voor HTTP rate limiting
set http_ratelimit {
type ipv4_addr
flags dynamic,timeout
timeout 1m
}
# Maximaal 30 nieuwe verbindingen per seconde per IP
tcp dport { 80, 443 } ct state new \
add @http_ratelimit { ip saddr \
limit rate over 30/second burst 50 packets } \
log prefix "nft-http-flood: " drop
Verbindingslimieten met ct count
Met ct count kun je het maximale aantal gelijktijdige verbindingen per IP beperken. Handig tegen slowloris-achtige aanvallen:
# Maximaal 10 gelijktijdige SSH-verbindingen per IP
set ssh_connlimit {
type ipv4_addr
flags dynamic
}
tcp dport 22 add @ssh_connlimit { ip saddr ct count over 10 } \
log prefix "nft-ssh-connlimit: " reject
# Maximaal 100 gelijktijdige HTTP-verbindingen per IP
set http_connlimit {
type ipv4_addr
flags dynamic
}
tcp dport { 80, 443 } add @http_connlimit { ip saddr ct count over 100 } \
drop
Named limits voor hergebruik
Je kunt limieten ook definiëren als herbruikbare objecten, wat je configuratie een stuk overzichtelijker maakt:
table inet firewall {
limit ssh_limit {
rate 4/minute
burst 6 packets
}
limit icmp_limit {
rate 5/second
burst 10 packets
}
chain input {
type filter hook input priority 0; policy drop;
tcp dport 22 ct state new limit name "ssh_limit" accept
ip protocol icmp limit name "icmp_limit" accept
}
}
Burst-parameters begrijpen
De burst-parameter is iets waar mensen vaak over struikelen, dus even een heldere uitleg. Stel je het voor als een emmer: de rate bepaalt hoe snel de emmer leegloopt, en burst bepaalt hoe groot de emmer is. Een burst van 6 packets bij een rate van 4/minute betekent dat een korte piek van 6 snelle verbindingen wordt toegestaan, waarna maximaal 4 per minuut worden doorgelaten.
Integratie met Fail2Ban
Hoewel dynamische sets in nftables al veel brute-force aanvallen afvangen, biedt Fail2Ban een extra laag. Het analyseert logbestanden en kan aanvallers blokkeren op basis van mislukte authenticatiepogingen — niet alleen verbindingsfrequentie. Hier is hoe je het opzet, stap voor stap.
Stap 1: nftables-tabel voor Fail2Ban aanmaken
Maak het bestand /etc/nftables.d/fail2ban.nft aan:
#!/usr/sbin/nft -f
# /etc/nftables.d/fail2ban.nft
# Tabel voor Fail2Ban — prioriteit 100 zorgt dat deze regels
# worden geëvalueerd vóór de hoofdregels
table ip fail2ban {
chain input {
type filter hook input priority 100; policy accept;
}
}
Stap 2: Inclusie in hoofdconfiguratie
Zorg ervoor dat je hoofdbestand /etc/nftables.conf de Fail2Ban-configuratie includeert. Als je de eerder getoonde configuratie met include "/etc/nftables.d/*.nft" gebruikt, wordt dit automatisch opgepikt. Niets extra's nodig.
Stap 3: Fail2Ban configureren voor nftables
Bewerk /etc/fail2ban/jail.local:
# /etc/fail2ban/jail.local
[DEFAULT]
banaction = nftables-multiport
chain = input
[sshd]
enabled = true
port = ssh
filter = sshd
backend = systemd
maxretry = 3
findtime = 600
bantime = 3600
ignoreip = 127.0.0.1/8 10.0.0.0/8
# Recidive jail — herhaalde overtreders langdurig blokkeren
[recidive]
enabled = true
backend = auto
logpath = /var/log/fail2ban.log
maxretry = 2
findtime = 86400
bantime = 604800
banaction = nftables-allports
Stap 4: nftables-common.local configureren
Maak het bestand /etc/fail2ban/action.d/nftables-common.local aan:
# /etc/fail2ban/action.d/nftables-common.local
[Init]
nftables_family = ip
nftables_table = fail2ban
blocktype = drop
nftables_set_prefix =
Stap 5: Systemd-afhankelijkheid configureren
Dit is een stap die veel mensen overslaan, maar die best belangrijk is. Je wilt dat Fail2Ban automatisch herstart wanneer nftables herstart — anders raak je je bans kwijt:
# Maak de override-directory aan
sudo mkdir -p /etc/systemd/system/fail2ban.service.d
# Maak de override aan
sudo tee /etc/systemd/system/fail2ban.service.d/override.conf <<EOF
[Unit]
Requires=nftables.service
PartOf=nftables.service
[Install]
WantedBy=multi-user.target nftables.service
EOF
# Herlaad systemd en herstart beide services
sudo systemctl daemon-reload
sudo systemctl restart nftables
sudo systemctl restart fail2ban
Stap 6: Verificatie
# Controleer de Fail2Ban-status
sudo fail2ban-client status sshd
# Bekijk de nftables-regels die Fail2Ban heeft aangemaakt
sudo nft list table ip fail2ban
# Bekijk gebande IP-adressen
sudo fail2ban-client get sshd banip --with-time
Geo-blocking met nftables
Geo-blocking voegt een extra beveiligingslaag toe door verkeer uit specifieke landen te blokkeren op IP-niveau. Is het waterdicht? Nee — aanvallers kunnen VPN's of gehackte servers in andere landen gebruiken. Maar het reduceert het aanvalsoppervlak aanzienlijk, vooral tegen geautomatiseerde scanners die het gros van het ongewenste verkeer uitmaken.
nft-geo-filter gebruiken
De tool nft-geo-filter is een script dat landenspecifieke IP-blokken downloadt en automatisch nftables-sets aanmaakt. Het mooie is dat het een aparte tabel gebruikt, waardoor je bestaande configuratie niet wordt verstoord.
# Installatie
git clone https://github.com/rpthms/nft-geo-filter.git
cd nft-geo-filter
# Blokkeer verkeer uit specifieke landen (ISO 3166-1 alpha-2 codes)
# Gebruik netdev-tabel voor maximale efficiëntie (2x sneller)
sudo ./nft-geo-filter \
--table-family netdev \
--interface eth0 \
--counter \
CN RU KP
# Gebruik inet-tabel als alternatief
sudo ./nft-geo-filter \
--table-family inet \
--counter \
CN RU KP
Handmatige geo-blocking met sets
Als je meer controle wilt (of het script niet aan je eisen voldoet), kun je handmatig sets aanmaken met IP-ranges per land:
table netdev geo_filter {
set blocked_countries_v4 {
type ipv4_addr
flags interval
# Deze ranges worden geladen vanuit een extern bestand
elements = { 1.0.1.0/24, 1.0.2.0/23, 1.0.8.0/21 }
}
chain ingress {
type filter hook ingress device "eth0" priority -190; policy accept;
# Drop verkeer uit geblokkeerde landen
ip saddr @blocked_countries_v4 counter drop
}
}
Automatische updates via cron
# /etc/cron.weekly/update-geoblock
#!/bin/bash
/opt/nft-geo-filter/nft-geo-filter \
--table-family netdev \
--interface eth0 \
CN RU KP \
2>&1 | logger -t nft-geoblock
Gebruik de netdev-tabel waar mogelijk. Volgens de nftables wiki is filteren via de netdev-familie tot 2x efficiënter dan via andere families, omdat pakketten worden verwerkt zodra ze door de netwerkkaart worden afgeleverd aan de kernel — nog vóór connection tracking. Dat is een flink verschil bij hoge verkeersvolumes.
Onthoud wel: geo-blocking is een aanvullende maatregel, geen vervanging voor proper firewall-beleid en tools als Fail2Ban. Zie het als een extra laag in je defense-in-depth strategie.
Migratie van iptables naar nftables
Als je bestaande servers hebt met iptables-regels, hoef je niet alles in één keer om te gooien. Gelukkig biedt nftables uitstekende migratietools.
iptables-translate: regel voor regel
Het commando iptables-translate vertaalt individuele iptables-regels naar nftables-syntax:
# Vertaal een enkele iptables-regel
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# Output: nft add rule ip filter INPUT tcp dport 22 counter accept
iptables-translate -A INPUT -s 192.168.1.0/24 -p tcp --dport 80 -j ACCEPT
# Output: nft add rule ip filter INPUT ip saddr 192.168.1.0/24 tcp dport 80 counter accept
# Werkt ook voor ip6tables
ip6tables-translate -A INPUT -p tcp --dport 443 -j ACCEPT
# Output: nft add rule ip6 filter INPUT tcp dport 443 counter accept
iptables-restore-translate: bulkconversie
Voor een volledige migratie exporteer je eerst je bestaande iptables-regels en vertaal je het geheel:
# Exporteer huidige iptables-regels
sudo iptables-save > /tmp/iptables-export.txt
# Vertaal het volledige regelset
sudo iptables-restore-translate -f /tmp/iptables-export.txt > /tmp/nftables-converted.nft
# Bekijk het resultaat
cat /tmp/nftables-converted.nft
# Test de vertaalde regels (zonder laden)
sudo nft -c -f /tmp/nftables-converted.nft
# Als alles goed is, laad de regels
sudo nft -f /tmp/nftables-converted.nft
Teststrategie
Mijn aanbeveling voor een veilige migratie (geleerd door schade en schande):
- Exporteer en vertaal de bestaande iptables-regels.
- Controleer de vertaalde regels handmatig — de vertaling is niet altijd perfect, met name bij complexe
-m recent- ofipset-regels. - Test eerst op een staging-server of in een VM.
- Gebruik
nft -c -fom syntax te valideren zonder de regels te laden. - Plan een onderhoudsvenster met console-toegang voor het geval je jezelf buitensluit.
- Schakel na succesvolle migratie het
iptables-nft-pakket uit om conflicten te voorkomen.
Stap 5 is geen grap, trouwens. Ik heb ooit een remote server buitengesloten door een fout in de firewallregels. Console-toegang (via IPMI, KVM of je hostingprovider's noodconsole) is je reddingsboei.
De iptables-nft compatibiliteitslaag
Tijdens de migratieperiode kun je de iptables-nft bridge gebruiken. Dit laat bestaande scripts en tools (inclusief Fail2Ban en Docker) hun vertrouwde iptables-commando's gebruiken, terwijl de regels achter de schermen door nftables worden verwerkt:
# Controleer welke backend actief is
sudo update-alternatives --display iptables
# Schakel naar iptables-nft (als dat nog niet het geval is)
sudo update-alternatives --set iptables /usr/sbin/iptables-nft
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
Monitoring en troubleshooting
Een firewall die je niet monitort is als een alarmsysteem dat op stil staat. Klinkt misschien dramatisch, maar het is echt zo. Hier zijn de tools en technieken die je nodig hebt.
Ruleset inspecteren
# Volledige ruleset tonen
sudo nft list ruleset
# Specifieke tabel tonen
sudo nft list table inet firewall
# Specifieke chain tonen
sudo nft list chain inet firewall input
# Toon regels met handles (nodig voor verwijdering)
sudo nft -a list ruleset
# Een regel verwijderen op basis van handle
sudo nft delete rule inet firewall input handle 42
Counters gebruiken
Voeg het counter-keyword toe aan regels om te zien hoeveel pakketten en bytes ze matchen:
# Voorbeeld met counters
tcp dport 22 ct state new counter accept
tcp dport { 80, 443 } counter accept
# Counters resetten
sudo nft reset counters table inet firewall
Packet tracing met nft monitor
Voor diepgaande debugging kun je packet tracing inschakelen. Dit is ongelooflijk handig als je niet snapt waarom bepaald verkeer wel of niet doorkomt:
# Stap 1: Voeg een trace-regel toe bovenaan je chain
sudo nft insert rule inet firewall input meta nftrace set 1
# Stap 2: Monitor de traces in een aparte terminal
sudo nft monitor trace
# Stap 3: Vergeet niet de trace-regel weer te verwijderen na debugging!
sudo nft -a list chain inet firewall input
# Noteer het handle-nummer van de trace-regel
sudo nft delete rule inet firewall input handle <nummer>
Syntaxvalidatie
# Valideer configuratiebestand zonder laden
sudo nft -c -f /etc/nftables.conf
# Bij succes: geen output. Bij fouten: duidelijke foutmelding met regelnummer.
Logging bekijken
Alle log-statements in nftables schrijven naar de kernel log, die je kunt bekijken via journald of syslog:
# Bekijk nftables-logberichten in real-time
sudo journalctl -k -f | grep "nft-"
# Specifiek SSH-denials bekijken
sudo journalctl -k --since "1 hour ago" | grep "nft-ssh-denied"
# Tellen van gedropt verkeer per prefix
sudo journalctl -k --since "24 hours ago" \
| grep "nft-input-dropped" | wc -l
Veelgemaakte fouten
Even een lijstje van fouten waar ik (en veel anderen) tegenaan ben gelopen:
- Vergeten
flush rulesetaan het begin van je configuratiebestand — dit zorgt ervoor dat oude regels blijven bestaan naast nieuwe. Leuk als je per ongeluk dubbele regels wilt. - Vergeten
ct state established,related accept— zonder deze regel worden antwoorden op je eigen uitgaande verbindingen geblokkeerd. Oeps. - Loopback-interface niet toestaan — veel services communiceren intern via localhost. Zonder
iif "lo" acceptbreek je deze communicatie. - ICMPv6 volledig blokkeren — IPv6 vereist ICMPv6 voor basisfunctionaliteit (Neighbor Discovery). Blokkeer je dit, dan werkt je IPv6-connectiviteit simpelweg niet meer.
- Mengen van iptables en nftables-commando's — dit leidt tot conflicterende regels die ongelooflijk moeilijk te debuggen zijn.
Veelgestelde vragen (FAQ)
Kan ik iptables en nftables tegelijkertijd gebruiken?
Technisch gezien is het mogelijk, maar het wordt sterk afgeraden. Beide systemen werken op dezelfde netfilter-infrastructuur in de kernel en hun regels kunnen conflicteren op onvoorspelbare manieren. Als je iptables-nft gebruikt (de standaard op de meeste moderne distributies), worden iptables-commando's intern vertaald naar nftables-regels. Je kunt dit controleren met iptables -V — als de output nf_tables bevat, gebruik je al de nftables-backend. De beste aanpak: migreer volledig naar nftables en verwijder het iptables-legacy-pakket.
Hoe maak ik nftables-regels persistent na een herstart?
Er zijn twee methoden. De eerste (en wat mij betreft de enige juiste) is om je regels op te slaan in /etc/nftables.conf en de nftables.service in te schakelen via systemd (sudo systemctl enable nftables). Bij het opstarten wordt dit bestand automatisch geladen. De tweede methode is om de huidige ruleset te exporteren met sudo nft list ruleset > /etc/nftables.conf, maar dit overschrijft eventuele commentaren en structuur die je handmatig hebt aangebracht. Behandel je configuratiebestand als broncode — inclusief versiebeheer via git.
Wat is het verschil tussen de inet en ip families?
De ip-familie verwerkt alleen IPv4-verkeer, terwijl ip6 alleen IPv6 verwerkt. De inet-familie combineert beide: je schrijft één set regels die automatisch voor zowel IPv4 als IPv6 geldt. Dit is in bijna alle gevallen de beste keuze voor servers. Er is één uitzondering: als je sets gebruikt met IP-adressen als type, moet je nog steeds aparte sets definiëren voor ipv4_addr en ipv6_addr — die typen kunnen niet worden gemengd in één set.
Hoe controleer ik of mijn server nftables of iptables gebruikt?
Gebruik de volgende commando's:
# Controleer of nftables actief is
sudo nft list ruleset
# Als dit regels toont, is nftables actief
# Controleer de iptables-backend
iptables -V
# "iptables v1.8.x (nf_tables)" = nftables-backend
# "iptables v1.8.x (legacy)" = oud iptables-framework
# Controleer de systemd-service
sudo systemctl status nftables
sudo systemctl status iptables
Is nftables sneller dan iptables?
Ja, met name bij grote regelsets. Bij iptables wordt elke chain lineair doorlopen — bij 500 regels moet elk pakket potentieel alle 500 regels passeren (O(n)). nftables gebruikt hash-gebaseerde sets, verdict maps en interne optimalisaties voor lookups in constante tijd (O(1)). In benchmarks is het verschil verwaarloosbaar bij kleine regelsets (minder dan 50 regels), maar aanzienlijk bij grotere configuraties. Daarnaast is het atomaire laden van regelsets in nftables sneller en veiliger dan het sequentieel toevoegen van regels via iptables-restore.
Voor servers met complexe firewall-configuraties, uitgebreide IP-lijsten of geo-blocking is nftables meetbaar sneller. En eerlijk? Zelfs bij kleine regelsets is de betere syntax het al waard.
Conclusie
nftables is in 2026 niet langer optioneel voor serieus Linux-serverbeheer — het is simpelweg de standaard, en met goede reden. De combinatie van een uniforme syntax, superieure performance en krachtige features als dynamische sets maakt het onmisbaar in elke server-hardening strategie.
De configuratie die we in deze gids hebben opgebouwd implementeert meerdere verdedigingslagen: een default-deny beleid, per-IP rate limiting in de kernel, ICMP-bescherming, logging van verdacht verkeer, Fail2Ban-integratie en optionele geo-blocking. Samen vormen ze een robuust schild tegen de dreigingen van het huidige landschap — van geautomatiseerde brute-force botnets tot gerichte aanvallen.
Mijn advies: begin vandaag. Pak de basisconfiguratie uit deze gids, pas de variabelen aan naar jouw situatie, test op een staging-omgeving en rol het uit. Controleer je firewall-logs wekelijks, update je geo-blocking databases, en behandel je /etc/nftables.conf als wat het is — een kritisch beveiligingsbestand dat net zoveel aandacht verdient als je SSH-configuratie.