J’ai commencé de l’extérieur, comme le ferait un utilisateur : nom tapé dans le navigateur d’un téléphone en données mobiles, puis j’ai regardé la connexion rester en attente jusqu’au délai d’expiration. Le nom se résolvait, donc le DNS était correct. La page de redirection de ports du routeur domestique était aussi une impasse, car son adresse WAN affichait 100.64.31.42, et ce n’est pas une adresse vers laquelle un fournisseur me routera depuis Internet. Ce nombre explique toute la panne : la ligne est derrière carrier-grade NAT, donc l’adresse publique de mon côté du tunnel appartient au fournisseur. Ce qui suit est le chemin que j’ai parcouru depuis cet onglet bloqué jusqu’à un service qui répond.

Partir du client et remonter vers l’intérieur

Avant de changer la moindre règle, prouvez où la chaîne s’arrête. Sur le portable, j’ai lancé dig +short files.example.net et obtenu l’adresse du VPS, ce qui écartait un DNS obsolète sur ma machine. Ensuite, curl -v --connect-timeout 5 files.example.net:5022 a expiré au lieu d’être refusé. Cette différence compte : un délai d’expiration signifie généralement que des paquets sont jetés en route, tandis qu’un refus signifie que quelque chose a répondu et dit non.

Le saut suivant vers l’intérieur était le VPS lui-même. ss -ltnp ne montrait rien à l’écoute sur 5022, ce qui était attendu avant l’existence de la règle DNAT. Sur la même machine, wg show (ou ip -br a show tun0 pour OpenVPN) a confirmé que le pair domestique était actif avec une poignée de main récente. Si le pair est hors ligne, aucune règle NAT n’aidera, et le voyant vert de la page VPN du routeur domestique ne veut rien dire.

Confirmer que la ligne domestique est bien derrière le CGNAT

Comparez l’adresse que le routeur annonce sur son interface WAN avec ce que voit un service extérieur. Tout ce qui est dans 100.64.0.0/10, c’est-à-dire 100.64.x.x à 100.127.x.x, appartient à la plage d’adresses partagées du RFC 6598 et n’est pas joignable depuis Internet. Vous arrivez à la même conclusion quand le routeur prétend avoir une adresse privée ordinaire et qu’une recherche publique renvoie autre chose. Une ligne CGNAT peut aussi fournir une adresse publique qui ne dure que jusqu’au prochain bail, si bien qu’une redirection de port semble fonctionner une heure puis meurt en silence.

Certains fournisseurs attribuent bien une vraie adresse publique mais bloquent les ports entrants 80 et 443 sur les comptes résidentiels. Si votre service est uniquement web et que l’adresse WAN est réellement publique, demandez au support avant de construire un relais. Sinon, la conception ci-dessous s’applique de la même façon à chaque port, et il vaut la peine d’arrêter l’expérience côté routeur : le traducteur du réseau du fournisseur termine la connexion avant qu’elle n’atteigne votre interface WAN.

Pointer le nom vers l’adresse du VPS

Le DNS ne relaie pas le trafic, donc l’enregistrement A du service doit contenir l’adresse publique du VPS. Un enregistrement A vers 192.168.1.20 ne se résout utilement que pour les clients déjà à l’intérieur du VPN ; depuis Internet, il se résout vers une adresse que personne ne peut router. Pour l’accès d’administration du VPS lui-même, je garde un nom distinct, afin de ne jamais confondre l’hôte vers lequel pointe un enregistrement.

Si le VPS et la machine domestique servent tous deux du HTTP, donnez à chacun son propre nom et laissez le VPS décider lequel répond. Les fondre en un seul nom et espérer que le proxy choisisse le bon backend, c’est exactement comme cela qu’on débogue le mauvais hôte pendant tout un après-midi.

Un seul port en DNAT, SSH reste sur 22

L’option directe est le NAT de destination sur le VPS. Activez le transfert pour le noyau en cours d’exécution et gardez l’adresse tunnel du serveur domestique dans la règle, pas son adresse LAN :

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp -d 198.51.100.10 --dport 5022 -j DNAT --to-destination 10.8.0.2

Laissez SSH vers le VPS lui-même sur 22 et redirigez un autre port, par exemple 5022, vers la machine domestique. Redirigez 22 vers une machine éteinte et vous perdez le seul chemin qui aurait pu la réparer. La même logique s’applique au proxy : laissez le port d’administration du VPS en dehors des règles de relais.

Rendez les règles persistantes une fois qu’elles fonctionnent. Sous Debian ou Ubuntu, apt install iptables-persistent puis netfilter-persistent save les écrivent dans /etc/iptables/rules.v4. Sur un hôte firewalld, l’équivalent est un transfert de port permanent sur la zone, qui nécessite firewall-cmd --reload avant de s’appliquer. Les règles qui ne vivent qu’en mémoire disparaissent au premier redémarrage de maintenance du fournisseur, généralement à une heure mal choisie.

Corriger la route de retour, ou éviter d’en avoir besoin

Le DNAT ne réécrit que la destination. Le serveur domestique voit une connexion venant de l’adresse du client d’origine, et si sa route par défaut pointe vers le routeur domestique, la réponse sort par le WAN de la maison où le traducteur du fournisseur la jette. Cette asymétrie fut la deuxième panne que j’ai rencontrée, après que la règle DNAT paraissait parfaitement correcte.

Deux correctifs fonctionnent. Donnez à la machine domestique une route politique pour que le trafic du tunnel reparte par le tunnel :

ip rule add from 10.8.0.2 table 100
ip route add default dev wg0 table 100

Ou laissez le VPS réécrire la source pour que la réponse ait une adresse qu’il peut joindre, et laissez conntrack l’inverser au retour :

iptables -t nat -A POSTROUTING -d 10.8.0.2 -p tcp --dport 5022 -j SNAT --to-source 10.8.0.1

La version SNAT cache l’adresse réelle du client au serveur domestique, donc les journaux applicatifs affichent 10.8.0.1 comme pair. Transmettez l’adresse d’origine au niveau applicatif, ou acceptez de perdre la journalisation par client, mais décidez-le délibérément plutôt que de le découvrir pendant un incident.

Vérifier tout le chemin depuis l’extérieur

Vérifiez depuis un réseau qui n’est ni le VPS ni la maison : un téléphone en données mobiles, ou un shell bon marché ailleurs. nc -vz files.example.net 5022 devrait signaler une connexion réussie, et openssl s_client -connect files.example.net:443 -servername files.example.net devrait afficher le certificat du nom public. Vérifiez ensuite le groupe de sécurité ou le pare-feu cloud du fournisseur. Une règle DNAT qui ne voit jamais de paquet est généralement bloquée une couche au-dessus de l’hôte.

Enfin, décidez de ce qui se passe quand le tunnel tombe. Une règle DNAT continue d’accepter des connexions et les enfouit silencieusement dans un tunnel mort, ce qui ressemble exactement à un service en panne. Un contrôle de santé sur le VPS qui refuse le port tant que le pair est hors ligne coûte quelques lignes et épargne une heure de conjectures. Ensuite, cessez de modifier les règles et observez pendant une journée avant de lui faire confiance.

Articles similaires