Votre VM est en NAT et vous voulez exposer un service (web, SSH, etc.) depuis l'extérieur ? Cette recette vous montre comment configurer le port forwarding selon votre firewall.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Poser une règle DNAT qui expose un port de la VM sur l'hôte
- Choisir entre firewalld, nftables et iptables selon votre système
- Distinguer votre backend de celui que libvirt utilise pour ses règles
- Rendre la règle persistante sans figer celles de l'hyperviseur
Prérequis
Section intitulée « Prérequis »Le point le plus important de cette liste est l'adresse fixe de la VM : une règle de redirection pointe une IP précise, et une VM qui change d'adresse au prochain bail DHCP renvoie le trafic vers le vide. Fixez-la côté invité, ou posez une réservation DHCP par adresse MAC dans le XML du réseau libvirt. Le reste se vérifie en une minute, mais la règle ne sera jamais posée si l'un des trois manque.
- VM en NAT avec une IP fixe ou connue (ex:
192.168.122.10) - Accès root sur l'hôte KVM
- Connaître le port à exposer (ex: 80 pour HTTP, 22 pour SSH)
Principe
Section intitulée « Principe »En NAT, les VMs ne sont pas joignables depuis l'extérieur : leur adresse 192.168.122.x n'est routée nulle part sur le LAN. Le port forwarding contourne cette limite sans changer de mode réseau, en redirigeant un port de l'hôte vers un port de la VM :
Internet → hôte:8080 → NAT DNAT → VM:80Configuration selon le firewall
Section intitulée « Configuration selon le firewall »La règle de redirection est toujours la même sur le fond : une règle DNAT qui réécrit l'adresse de destination des paquets arrivant sur un port de l'hôte. Ce qui change, c'est l'outil qui la porte. Les trois onglets ci-dessous donnent la même configuration dans les trois systèmes de pare-feu que vous rencontrerez sur un hôte KVM. Identifiez le vôtre avant de copier quoi que ce soit : empiler deux méthodes produit des règles concurrentes impossibles à démêler ensuite.
Deux questions différentes, à ne pas confondre
Section intitulée « Deux questions différentes, à ne pas confondre »Avant de choisir un onglet, distinguez ce que vous utilisez, vous, pour écrire vos règles, et ce que libvirt utilise, lui, pour poser les siennes. Ce sont deux réglages indépendants, et les confondre mène à chercher des règles là où elles ne sont pas.
Depuis la version 10.4, libvirt sait poser ses règles nativement en
nftables, et il ne les écrit alors pas dans les tables génériques filter
et nat : il crée sa propre table, nommée libvirt_network. La commande
qui tranche est donc celle-ci :
sudo nft list tables | grep libvirtUne ligne table ip libvirt_network signifie que libvirt gère ses règles en
nftables natif. Aucune ligne signifie qu'il passe encore par
iptables, et ses règles vivent alors dans des chaînes préfixées LIBVIRT_ :
sudo iptables -S | grep -oE 'LIBVIRT_[A-Z]+' | sort -uLe réglage côté libvirt se lit et se change dans /etc/libvirt/network.conf,
quand la version l'expose :
firewall_backend = "nftables"firewalld est le firewall par défaut sur RHEL 9, Fedora, Rocky, Alma.
Vérifier que firewalld est actif
Section intitulée « Vérifier que firewalld est actif »La sortie doit indiquer active (running). Si le service est inactif, les
règles ajoutées plus bas ne seront pas appliquées.
systemctl status firewalldAjouter une règle de port forwarding
Section intitulée « Ajouter une règle de port forwarding »La première commande agit sur la configuration en cours uniquement : elle disparaîtrait au redémarrage. La seconde recopie l'état courant dans la configuration permanente, ce qui évite d'avoir à saisir la règle deux fois, une fois pour le noyau et une fois pour le fichier.
# Rediriger le port 8080 de l'hôte vers le port 80 de la VMsudo firewall-cmd --zone=public --add-forward-port=port=8080:proto=tcp:toaddr=192.168.122.10:toport=80
# Rendre la règle permanentesudo firewall-cmd --runtime-to-permanentVérifier
Section intitulée « Vérifier »La sortie doit reprendre la redirection exactement telle que vous l'avez
saisie. Une sortie vide signifie que la règle a été posée sur une autre
zone : firewalld range ses règles par zone, et cette commande n'affiche que
celles de public.
sudo firewall-cmd --zone=public --list-forward-portsSupprimer la règle
Section intitulée « Supprimer la règle »Le retrait doit reprendre les quatre paramètres à l'identique, sinon
firewalld ne reconnaît pas la règle à supprimer. Ici --permanent vise le
fichier de configuration, d'où le --reload qui recharge la configuration
en cours à partir de ce fichier.
sudo firewall-cmd --zone=public --remove-forward-port=port=8080:proto=tcp:toaddr=192.168.122.10:toport=80 --permanentsudo firewall-cmd --reloadnftables remplace iptables sur les distributions modernes.
Vérifier que nftables est actif
Section intitulée « Vérifier que nftables est actif »Le second affichage est le plus utile : il montre les tables et chaînes déjà en place. Sur un hôte KVM, libvirt y a en général posé ses propres règles, celles qui portent le NAT du réseau default : les remplacer par un jeu écrit à la main couperait l'accès Internet de toutes vos VMs.
systemctl status nftablessudo nft list ruleset | head -20Ajouter une règle de port forwarding
Section intitulée « Ajouter une règle de port forwarding »Les deux règles sont indispensables et se complètent. La première réécrit l'adresse de destination, la seconde autorise le paquet réécrit à traverser l'hôte. Sans elle, la redirection a bien lieu mais le paquet est jeté juste après, ce qui se traduit côté client par un délai d'attente et non par un refus de connexion.
# Créer la règle DNATsudo nft add rule ip nat PREROUTING tcp dport 8080 dnat to 192.168.122.10:80
# Autoriser le forwardsudo nft add rule ip filter FORWARD ip daddr 192.168.122.10 tcp dport 80 acceptPersister les règles
Section intitulée « Persister les règles »Les règles ajoutées avec nft add vivent en mémoire et disparaissent au
redémarrage. La tentation est d'écrire tout le jeu de règles courant dans le
fichier de démarrage, et c'est précisément ce qu'il ne faut pas faire :
# ❌ fige aussi les regles de libvirt, qui les recreera au demarragesudo nft list ruleset > /etc/nftables.confCe fichier contiendrait les règles générées par libvirt, qui les repose lui-même à chaque démarrage de ses réseaux. Vous obtiendriez des règles en double, figées dans un état qui ne correspond plus au sien dès qu'un réseau change, et impossibles à démêler ensuite.
La bonne pratique est d'écrire votre propre table, que vous possédez et que libvirt ne touchera jamais. Elle porte vos règles, et elle seule :
table ip monlab { chain prerouting { type nat hook prerouting priority dstnat; policy accept; tcp dport 8080 dnat to 192.168.122.100:80 } chain forward { type filter hook forward priority filter; policy accept; ip daddr 192.168.122.100 tcp dport 80 accept }}Le nom monlab vous appartient, les priorités dstnat et filter
placent vos chaînes au bon moment du traitement, et le fichier se charge au
démarrage par la configuration de nftables.service. Vos règles survivent au
redémarrage sans jamais se mélanger à celles de l'hyperviseur.
Vérifier
Section intitulée « Vérifier »La chaîne doit contenir la règle dnat que vous venez d'ajouter. Si la commande
répond qu'aucune chaîne de ce nom n'existe, c'est que la table de
traduction d'adresses n'a jamais été créée sur ce système : l'ajout précédent a
donc échoué de la même façon, et la redirection n'a jamais été posée.
sudo nft list chain ip nat PREROUTINGiptables est encore utilisé sur certaines distributions ou configurations legacy.
Ajouter une règle de port forwarding
Section intitulée « Ajouter une règle de port forwarding »Même logique qu'avec nftables, avec une syntaxe différente : -t nat désigne la
table de traduction d'adresses, l'absence de -t dans la seconde commande
vise la table filter par défaut. L'ordre compte, -A ajoute la règle à la
fin de la chaîne : si une règle antérieure rejette déjà ce trafic, la vôtre ne
sera jamais atteinte.
# Rediriger le port 8080 de l'hôte vers le port 80 de la VMsudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.122.10:80
# Autoriser le forwardsudo iptables -A FORWARD -p tcp -d 192.168.122.10 --dport 80 -j ACCEPTPersister les règles
Section intitulée « Persister les règles »iptables ne sauvegarde rien de lui-même : sans l'un des paquets ci-dessous, les règles sont perdues au prochain redémarrage. La procédure diffère selon la famille de distribution, le paquet ne portant ni le même nom ni la même commande de sauvegarde sur Debian et sur RHEL.
sudo apt install iptables-persistentsudo netfilter-persistent savesudo dnf install iptables-servicessudo service iptables saveVérifier
Section intitulée « Vérifier »Le -n évite les résolutions DNS, qui rendent l'affichage lent et trompeur.
Le -v ajoute les compteurs de paquets : s'ils restent à zéro alors que
vous testez depuis l'extérieur, le trafic n'atteint même pas cette règle et le
problème se situe en amont.
sudo iptables -t nat -L PREROUTING -n -vsudo iptables -L FORWARD -n -vSupprimer la règle
Section intitulée « Supprimer la règle »-D supprime une règle décrite exactement comme elle a été ajoutée :
reprenez la ligne d'origine en remplaçant le seul -A par -D. Le moindre
écart, un port, un protocole ou une adresse, et iptables répond que la règle
n'existe pas alors qu'elle est bien en place.
sudo iptables -t nat -D PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.122.10:80sudo iptables -D FORWARD -p tcp -d 192.168.122.10 --dport 80 -j ACCEPTVérifier que ça fonctionne
Section intitulée « Vérifier que ça fonctionne »Le test doit impérativement partir d'une autre machine que l'hôte KVM. Un
curl lancé depuis l'hôte lui-même emprunte la chaîne OUTPUT et non
PREROUTING : il peut réussir alors que la redirection est cassée pour le
reste du réseau, ou échouer alors qu'elle fonctionne. Vérifiez aussi que le
service écoute sur toutes les interfaces de la VM, et pas uniquement sur
127.0.0.1.
curl http://<ip-hote>:8080# Doit afficher la page web de la VMDépannage
Section intitulée « Dépannage »Ces trois symptômes se distinguent facilement l'un de l'autre, à condition de lire le message d'erreur. Un refus immédiat signifie que le paquet est arrivé quelque part et qu'on lui a répondu, donc que la redirection fonctionne au moins en partie. Un délai d'attente signifie au contraire qu'aucune réponse n'est revenue : le paquet est perdu en chemin.
| Problème | Cause probable | Solution |
|---|---|---|
| Connection refused | Service non démarré dans la VM | Vérifier que le service écoute sur le bon port |
| Connection timeout | Règle mal appliquée | Vérifier les règles avec iptables -L ou nft list |
| Marche en local, pas en externe | Firewall hôte bloque | Ouvrir le port sur l'interface externe |
Alternative : utiliser un bridge
Section intitulée « Alternative : utiliser un bridge »Si vous avez besoin d'exposer plusieurs services ou de simplifier la configuration, envisagez de passer en mode bridge. Voir le guide réseau KVM.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications