I – Objectif
Ce guide explique comment construire, valider et faire persister un pare-feu nftables sur un hôte Linux (Debian ou Ubuntu). Le but : un pare-feu dual-stack (IPv4 et IPv6) simple, lisible et sûr, que tu adapteras à tes propres services. Il est volontairement progressif et autonome : concepts, installation, exemple complet commenté, persistance, diagnostic et migration.
● un accès root ou sudo
● un noyau récent (nf_tables est le moteur par défaut depuis Debian 10 et Ubuntu 20.04)
● surtout, la liste des ports que la machine doit réellement exposer
● sur une machine distante, prépare un accès console de secours AVANT toute manipulation (voir la section anti-lockout)
Avertissement. L'exemple de pare-feu de ce guide est un modèle pédagogique. Il n'est pas à copier tel quel : adapte-le à tes services réels (ports ouverts, interfaces, adresses d'administration). Ouvrir 80/443 sur une machine qui n'héberge pas de site, ou oublier un service métier, sont des erreurs classiques.
II – nftables vs iptables : l'essentiel
nftables est le successeur d'iptables au sein du projet netfilter. Il remplace iptables, ip6tables, arptables et ebtables par un seul outil : nft. Les différences qui comptent au quotidien :
• Un seul outil, une seule syntaxe pour IPv4, IPv6, ARP et bridge, proche de tcpdump/pf.
• Rien n'est préinstallé : pas de table filter ni de chaîne INPUT par défaut. Tu crées explicitement tes tables et tes chaînes — ce qui rend la configuration lisible et reproductible.
• La famille inet traite IPv4 et IPv6 dans une seule table : plus besoin de dupliquer chaque règle.
• Rechargement atomique : un fichier nft -f est appliqué en une seule transaction. En cas d'erreur, rien n'est appliqué — pas d'état intermédiaire dangereux.
• Sets et maps natifs, compteurs à la demande, et suppression de règle par handle (identifiant stable) plutôt que par numéro de ligne fragile.
Sur Debian/Ubuntu modernes, la commande iptables est en réalité un habillage au-dessus de nftables (backend iptables-nft). iptables -V affiche alors nf_tables. Voir la section coexistence.
III – Concepts : familles, table, chaîne, règle, hooks
Familles : ip (IPv4), ip6 (IPv6), inet (les deux), arp, bridge, netdev. Pour un pare-feu d'hôte dual-stack, on utilise inet.
Table : un conteneur nommé, rattaché à une famille (ex. table inet filter). Chaîne : une liste ordonnée de règles dans une table. Une chaîne de base est rattachée à un hook du noyau et reçoit le trafic ; une chaîne ordinaire ne sert qu'à regrouper des règles appelées par jump/goto.
Hooks (points d'accroche dans le noyau) : prerouting, input, forward, output, postrouting. Pour filtrer ce qui arrive à la machine, on utilise input ; ce qui part de la machine, output ; ce qui transite (routeur), forward.
Priorité : quand plusieurs chaînes de base partagent un hook, la priorité (un entier, du plus petit au plus grand) fixe l'ordre. Des noms standards existent :
• raw (-300) : avant le suivi de connexion
• mangle (-150) : modification d'en-têtes
• dstnat (-100) : NAT destination (prerouting)
• filter (0) : filtrage classique
• security (50) : règles de sécurité
• srcnat (100) : NAT source (postrouting)
Policy (verdict par défaut) d'une chaîne de base : accept ou drop. C'est le sort d'un paquet qui n'a été accepté par aucune règle. Un pare-feu restrictif pose policy drop sur input et forward, puis autorise explicitement le nécessaire.
IV – Installation (Debian / Ubuntu)
sudo apt update
sudo apt install nftables
À ce stade, on installe uniquement le paquet. Le service nftables.service charge le fichier /etc/nftables.conf au démarrage : on ne l'activera qu'après avoir écrit, validé puis chargé notre configuration finale (voir la section Persistance). Sur une installation neuve, /etc/nftables.conf ne contient qu'un squelette minimal, sans policy restrictive.
V – Inspecter l'existant
Avant de toucher quoi que ce soit, regarde ce qui tourne déjà. Une machine peut avoir des règles posées par UFW, firewalld ou Docker.
sudo nft list ruleset
sudo nft list tables
sudo nft -a list ruleset
VI – Sauvegarder avant de toucher
sudo sh -c '{ echo "flush ruleset"; nft list ruleset; } > /root/nft-backup-2026-08-21.nft'
Le fichier produit commence par flush ruleset puis contient tout le jeu de règles actuel : il est autonome. Pour revenir exactement à cet état : sudo nft -f /root/nft-backup-2026-08-21.nft — rien à ajouter à la main, le flush est déjà en tête et le rechargement est atomique.
VII – Filet anti-lockout SSH
● Danger. Sur une machine distante, une policy drop mal réglée te coupe l'accès SSH — définitivement si tu n'as pas de filet. Ne charge jamais un nouveau jeu de règles à l'aveugle.
Trois protections, à combiner :
1. Une console de secours hors-bande (KVM/console web de l'hébergeur, IPMI). C'est le vrai filet : elle ne dépend pas du réseau filtré.
2. Garder la session en cours ouverte et tester la nouvelle config depuis une seconde connexion SSH. Si la 2e passe, tu peux fermer sereinement.
3. Un rollback programmé : planifie la restauration automatique de l'ancienne config, annule-la seulement si SSH tient toujours.
sudo systemd-run --unit=nftables-rollback --on-active=120 /usr/sbin/nft -f /root/nft-backup-2026-08-21.nft
sudo nft -f /etc/nftables.conf
sudo systemctl stop nftables-rollback.timer
VIII – Exemple complet : pare-feu hôte dual-stack
Voici un /etc/nftables.conf commenté pour un serveur exposant SSH (22) et un service web (80/443). Il autorise la boucle locale, les réponses aux connexions sortantes, l'ICMP utile et — point crucial — l'ICMPv6 nécessaire au bon fonctionnement d'IPv6. SSH est autorisé avant le policy drop.
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iif "lo" accept
icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded, parameter-problem } limit rate 10/second accept
icmpv6 type { echo-request, echo-reply, destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld-listener-query, mld-listener-report, mld-listener-done } accept
tcp dport 22 accept
tcp dport { 80, 443 } accept
limit rate 5/minute log prefix "nft-drop-input " counter
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Pourquoi l'ICMPv6 est autorisé largement : IPv6 repose sur la découverte de voisins (NDP) et la découverte de MTU de chemin (PMTUD). Bloquer icmpv6 casse silencieusement la connectivité IPv6 (résolution d'adresses, gros paquets). C'est l'erreur la plus fréquente — d'où sa mise en avant ici.
IX – Valider puis charger (atomicité)
sudo nft -c -f /etc/nftables.conf
sudo nft -f /etc/nftables.conf
Le flush ruleset en tête de fichier suivi des nouvelles règles constitue une transaction unique : si une ligne est erronée, nft rejette tout le fichier et l'ancien jeu de règles reste en place. C'est ce qui rend un rechargement complet sûr — à condition de -c d'abord.
● À ne pas faire. Ne lance jamais un flush ruleset isolé à distance (dans une commande interactive séparée) : tu supprimes toutes tes règles d'un coup, policy comprise, et tu peux perdre l'accès. Le flush n'est sûr qu'à l'intérieur d'un fichier complet chargé d'un bloc avec nft -f, et avec le filet anti-lockout en place.
X – Persistance (systemd)
La configuration ci-dessus vit dans /etc/nftables.conf. Il suffit d'activer le service pour qu'elle soit chargée à chaque démarrage :
sudo systemctl enable --now nftables.service
sudo systemctl status nftables.service
Le fichier doit commencer par la ligne #!/usr/sbin/nft -f. Un simple nft -f /etc/nftables.conf recharge la config après édition, sans redémarrer.
XI – Ajouter et supprimer des règles (handles)
Pour un test rapide à chaud, sans réécrire le fichier. Ces changements sont volatils : reporte-les dans /etc/nftables.conf pour qu'ils survivent au reboot.
sudo nft add rule inet filter input tcp dport 8080 accept
sudo nft insert rule inet filter input tcp dport 8080 accept
sudo nft -a list chain inet filter input
sudo nft delete rule inet filter input handle 8
XII – Compteurs, logs et diagnostic
Ajoute counter à une règle pour compter paquets et octets. Combine log avec limit rate pour tracer sans noyer les journaux (comme dans l'exemple).
sudo nft list ruleset
sudo journalctl -k -g nft-drop-input --no-pager
Un service qui ne répond pas ? Vérifie que son port est bien accepté avant le drop, regarde le compteur de la règle drop, et confirme que le paquet arrive sur la bonne famille (IPv4 vs IPv6) — une des deux piles peut être filtrée sans que tu t'en rendes compte.
XIII – Sets nommés
Un set regroupe des valeurs (adresses, ports) sous un nom, mises à jour sans réécrire les règles. Exemple : n'autoriser SSH que depuis des IP d'administration.
table inet filter {
set admin_v4 {
type ipv4_addr
flags interval
elements = { 203.0.113.10, 198.51.100.0/24 }
}
chain input {
tcp dport 22 ip saddr @admin_v4 accept
}
}
sudo nft add element inet filter admin_v4 { 203.0.113.11 }
Le drapeau flags interval est requis pour stocker des plages/CIDR. Pense au set IPv6 équivalent (type ipv6_addr) si tu administres aussi en IPv6.
XIV – NAT (avertissement)
À adapter absolument. Le NAT concerne un routeur/passerelle, pas un simple hôte. L'exemple ci-dessous suppose une machine qui route un réseau interne vers Internet via eth0. Adapte les interfaces, active le forwarding et autorise le trafic dans la chaîne forward, sinon rien ne passe.
table inet nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "eth0" masquerade
}
}
sudo sysctl -w net.ipv4.ip_forward=1
XV – Coexistence et migration
iptables-nft : sur Debian/Ubuntu récents, iptables/ip6tables écrivent en réalité dans nftables. iptables -V montre nf_tables. Tu peux traduire d'anciennes règles avec iptables-translate puis les consolider dans un fichier nft.
UFW et firewalld peuvent s'appuyer sur nftables, selon la distribution et leur configuration (firewalld dispose d'un backend nftables ; UFW passe souvent par iptables-nft) — ce n'est pas systématique. Dans tous les cas, ne mélange pas des règles écrites à la main avec un gestionnaire actif : soit tu laisses UFW/firewalld piloter, soit tu les désactives et tu gères ton /etc/nftables.conf. Sinon, l'ordre des tables/priorités devient imprévisible.
Docker. Selon sa version et sa configuration, Docker gère le filtrage via iptables (backend iptables-nft) ou directement via nftables, en installant ses propres chaînes et en manipulant le NAT et le forward. Publier un port de conteneur (-p 8080:80) ouvre ce port via le hook forward, en contournant ton filtrage input : ton pare-feu hôte ne protège pas ces ports. Ne réécris pas les chaînes Docker à la main ; restreins plutôt l'exposition côté Docker (bind sur 127.0.0.1) ou via sa configuration dédiée.
XVI – Bonnes pratiques
• Toujours nft -c -f avant d'appliquer, et un filet anti-lockout à distance.
• policy drop sur input/forward, puis on ouvre explicitement (moindre privilège).
• Autoriser dans l'ordre : lo, established,related, l'ICMP utile, l'ICMPv6, puis les services — SSH avant le drop.
• Ne jamais casser l'ICMPv6 : NDP et PMTUD en dépendent.
• Un seul fichier versionnable, rechargé atomiquement ; commenter chaque bloc.
• Compteurs + logs limités pour diagnostiquer ; adapter les ports aux services réels.
• Ne pas mélanger nft manuel avec UFW, firewalld ou Docker.
XVII – Sources officielles