Aller au contenu
English
English
Virtualisation medium

Port forwarding NAT : exposer un service depuis une VM KVM

30 min de lecture

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.

  • 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

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)

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:80

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.

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 :

Fenêtre de terminal
sudo nft list tables | grep libvirt

Une 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_ :

Fenêtre de terminal
sudo iptables -S | grep -oE 'LIBVIRT_[A-Z]+' | sort -u

Le 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.

La sortie doit indiquer active (running). Si le service est inactif, les règles ajoutées plus bas ne seront pas appliquées.

Fenêtre de terminal
systemctl status firewalld

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.

Fenêtre de terminal
# Rediriger le port 8080 de l'hôte vers le port 80 de la VM
sudo firewall-cmd --zone=public --add-forward-port=port=8080:proto=tcp:toaddr=192.168.122.10:toport=80
# Rendre la règle permanente
sudo firewall-cmd --runtime-to-permanent

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.

Fenêtre de terminal
sudo firewall-cmd --zone=public --list-forward-ports

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.

Fenêtre de terminal
sudo firewall-cmd --zone=public --remove-forward-port=port=8080:proto=tcp:toaddr=192.168.122.10:toport=80 --permanent
sudo firewall-cmd --reload

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.

Fenêtre de terminal
curl http://<ip-hote>:8080
# Doit afficher la page web de la VM

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èmeCause probableSolution
Connection refusedService non démarré dans la VMVérifier que le service écoute sur le bon port
Connection timeoutRègle mal appliquéeVérifier les règles avec iptables -L ou nft list
Marche en local, pas en externeFirewall hôte bloqueOuvrir le port sur l'interface externe

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.

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

6 questions
6 min.
70% requis

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

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn