Tout fonctionne sur le LAN. SSH fonctionne, HTTP fonctionne, DNS semble sain. Puis vous testez depuis « l’extérieur » (VPN, point d’accès mobile, réseau partenaire, Internet réel) et c’est mort. Ou pire : ça marche à moitié, avec des délais qui donnent l’impression d’une farce.
Ce motif de panne n’est que rarement « l’application ». Il s’agit presque toujours de routage, NAT, filtrage, ou d’un décalage discret entre ce que vous pensez être le chemin et ce que font réellement les paquets à 2h du matin. Le remède n’est pas magique. Il est méthodique, guidé par des captures, et un peu impitoyable avec les hypothèses.
Le modèle mental : pourquoi le succès sur LAN ne prouve presque rien
Quand un service « fonctionne sur LAN », vous avez prouvé exactement une chose : quelque chose peut l’atteindre par un chemin directement accessible avec une traduction minimale et souvent une politique de pare-feu plus simple. Le trafic LAN a tendance à être :
- Monosaut ou petit nombre de sauts (le routage est plus simple).
- Souvent non NATé (ou le NAT se comporte différemment).
- Moins susceptible de traverser des middleboxes à états avec des timeouts stricts.
- Moins susceptible de subir du routage asymétrique (le chemin de retour est généralement évident).
- Moins susceptible de déclencher des règles de durcissement exposées sur Internet.
Le trafic WAN ajoute des couches : routeurs de périmètre, CPE ISP, groupes de sécurité, load balancers cloud et NAT — parfois plusieurs NAT empilés comme des pancakes faits de tristesse.
L’astuce diagnostique est d’arrêter de penser en termes de « le client ne se connecte pas » et de commencer à penser en termes de phases du paquet :
- Ingress : Est-ce que la requête SYN/UDP arrive sur l’interface du serveur que vous attendez ?
- Politique locale : Linux l’accepte-t-il (pare-feu, rp_filter, conntrack) ?
- Bouclage du service : L’application est-elle liée à la bonne IP/port et accessible via ce chemin ?
- Chemin de retour : La réponse sort-elle via le même bord (ou au moins via une interface routable) ?
- Translation : Le NAT réécrit-il les bonnes adresses/ports et suit-il correctement l’état ?
Si vous pouvez répondre à ces cinq points, vous pouvez généralement nommer la cause racine avec confiance, pas au feeling.
Playbook de diagnostic rapide (premier/deuxième/troisième)
Premier : prouver si les paquets atteignent la machine
Effectuez une capture sur l’interface publique pendant que vous tentez une connexion depuis le WAN. Si vous ne voyez pas de paquets entrants, le problème est en amont (NAT/forward du bord, pare-feu de l’ISP, groupe de sécurité cloud, mauvaise IP publique).
Second : prouver si la machine répond et où vont les réponses
Si vous voyez le SYN arriver, cherchez immédiatement le SYN-ACK sortant. S’il sort par une interface différente de celle attendue, vous êtes en terrain de routage asymétrique/policy routing. Si aucune réponse ne sort, vous êtes en territoire pare-feu/rp_filter/bind d’application.
Troisième : prouver l’état et la traduction
Si vous voyez des réponses sortir mais que le client ne les reçoit jamais, regardez l’état NAT (conntrack) et les équipements intermédiaires. Beaucoup de cas « WAN échoue » sont dus au trafic de retour NATé incorrectement, droppé à cause de rp_filter, ou échouant à cause de problèmes MTU/MSS sur le chemin WAN.
Règle d’opinion : N’« ajoutez pas juste une règle ». Capturez d’abord, changez ensuite. Sinon vous accumulerez des correctifs et perdrez la capacité de raisonner sur le système.
Faits intéressants et contexte historique (9 points rapides)
- Le NAT n’était pas le plan initial. Il est devenu populaire dans les années 1990 lorsque la pénurie d’adresses IPv4 a rencontré le haut débit grand public.
- netfilter Linux est arrivé à l’époque du noyau 2.4. Il a remplacé ipchains et rendu le filtrage à état courant sur Linux.
- conntrack est de la mémoire d’état. Le NAT dépend du suivi de connexion ; si conntrack est plein, des échecs « aléatoires » apparaissent qui ne sont pas vraiment aléatoires.
- rp_filter existe pour lutter contre l’usurpation. Le filtrage du chemin inverse droppe les paquets qui « ne devraient pas » arriver sur une interface, ce qui est utile jusqu’à ce que vous ayez du routage asymétrique ou du policy routing.
- La découverte automatique du MTU (PMTUD) est fragile depuis des décennies. Le filtrage des ICMP « Fragmentation Needed » casse PMTUD, conduisant à des blocages uniquement sur WAN et à des bugs « mystères » MSS/MTU.
- Le hairpin NAT est un type particulier d’ennui. Accéder à un service via son IP publique depuis l’intérieur du même NAT peut échouer à moins que le routeur ne supporte la réflexion/hairpinning.
- nftables n’a pas tué iptables du jour au lendemain. Beaucoup de distributions exécutent iptables comme couche de compatibilité sur nftables, ce qui peut embrouiller le débogage si vous ne vérifiez pas ce qui est réellement actif.
- Les routes par défaut sont politiques. Les hôtes multi-homed (deux uplinks) ont besoin de policy routing explicite ; sinon Linux choisit la « meilleure » route qui n’est meilleure que dans sa propre logique.
- UDP « marche sur LAN » n’équivaut pas à « marche sur WAN ». Les timeouts NAT et les pare-feu à états traitent UDP comme un insecte éphémère.
Tâches pratiques : commandes, sorties et décisions (14 tâches)
Toutes les tâches supposent Debian/Ubuntu côté serveur sauf indication contraire. Remplacez les noms d’interface, IP et ports par vos valeurs. L’intérêt est la forme des preuves.
Task 1: Confirm the service is listening on the right IP and port
cr0x@server:~$ sudo ss -lntup | grep -E '(:80|:443|:22)\b'
tcp LISTEN 0 4096 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1432,fd=6))
tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=911,fd=3))
tcp LISTEN 0 4096 [::]:443 [::]:* users:(("nginx",pid=1432,fd=7))
Ce que cela signifie : Si vous voyez 127.0.0.1:80 ou une adresse privée uniquement, le WAN ne fonctionnera pas (l’application n’est pas liée au chemin public). Si vous voyez seulement [::]:443 et que votre test WAN est en IPv4, vous écoutez peut-être uniquement en IPv6 ou inversement.
Décision : Corrigez d’abord les adresses de liaison. Ne touchez pas au NAT tant que le service n’est pas réellement accessible sur l’interface/IP attendu.
Task 2: Verify local firewall policy (nftables/iptables/UFW) without guessing
cr0x@server:~$ sudo nft list ruleset | sed -n '1,140p'
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif "lo" accept
tcp dport { 22, 80, 443 } accept
ip protocol icmp accept
counter drop
}
}
Ce que cela signifie : Politique drop par défaut avec autorisations explicites, c’est acceptable. L’absence de votre port de service n’est pas acceptable. Si vous utilisez UFW, il peut gérer des règles en coulisse, mais nft montre ce qui est réellement actif.
Décision : Si des connexions WAN atteignent directement cet hôte, ouvrez le port ici. Si le trafic est DNATé vers une machine interne, ouvrez-le aussi sur l’hôte de destination.
Task 3: Check whether iptables is really nftables in disguise
cr0x@server:~$ sudo iptables -V
iptables v1.8.9 (nf_tables)
Ce que cela signifie : Vos commandes iptables peuvent manipuler le backend nftables. C’est acceptable, mais mélanger les outils « legacy » et « nf_tables » peut produire des règles que vous ne voyez pas là où vous cherchez.
Décision : Choisissez une vue (préférez nft list ruleset) et tenez-vous-y pendant le débogage.
Task 4: Confirm the routing table and default route on the server
cr0x@server:~$ ip route
default via 203.0.113.1 dev eth0 proto dhcp src 203.0.113.20 metric 100
10.10.0.0/24 dev eth1 proto kernel scope link src 10.10.0.10
203.0.113.0/24 dev eth0 proto kernel scope link src 203.0.113.20
Ce que cela signifie : Le serveur pense que les réponses vers Internet sortent par eth0 via 203.0.113.1. Si votre chemin WAN est en fait via une autre interface, vous avez trouvé un problème central.
Décision : Si vous êtes multi-homed, préparez-vous à utiliser du policy routing (ip rule) plutôt que « d’espérer » que Linux choisisse l’interface souhaitée.
Task 5: Inspect policy routing rules (the silent kingmakers)
cr0x@server:~$ ip rule show
0: from all lookup local
100: from 10.10.0.0/24 lookup 100
32766: from all lookup main
32767: from all lookup default
Ce que cela signifie : Le trafic provenant de 10.10.0.0/24 utilise la table de routage 100. Cela peut causer des échecs WAN si le trafic de retour pour une connexion WAN utilise la mauvaise source IP ou le mauvais uplink.
Décision : Si un service WAN est DNATé vers 10.10.0.10, assurez-vous que les réponses retournent par l’interface que le client peut réellement atteindre, généralement la même passerelle NAT.
Task 6: Check rp_filter (reverse path filtering), the classic “WAN only” assassin
cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.eth0.rp_filter net.ipv4.conf.eth1.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
Ce que cela signifie : Le mode strict (1) droppe les paquets si le noyau pense que le chemin de retour n’utiliserait pas la même interface. Le routage asymétrique ou le policy routing peuvent entraîner des drops avant même que votre pare-feu n’ait voix au chapitre.
Décision : Si vous avez du routage asymétrique par conception (multi-uplink, VRF, policy routing), mettez rp_filter en mode lâche (2) sur les interfaces concernées, ou désactivez prudemment (0) là où c’est approprié.
Task 7: Prove packets arrive: tcpdump on the WAN-facing interface
cr0x@server:~$ sudo tcpdump -ni eth0 'tcp port 443 and (tcp[tcpflags] & (tcp-syn) != 0)'
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:44:10.101010 IP 198.51.100.88.50122 > 203.0.113.20.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 101 ecr 0,nop,wscale 7], length 0
Ce que cela signifie : Le SYN arrive. Le routage en amont et l’IP publique sont corrects. Maintenant la balle est dans votre camp : politique locale, NAT ou routage de retour.
Décision : Si vous ne voyez pas de paquets, arrêtez d’éditer le serveur. Corrigez le NAT de bord, les groupes de sécurité, le pare-feu en amont, ou la situation de « mauvaise IP publique ».
Task 8: Prove replies leave: capture SYN and SYN-ACK together
cr0x@server:~$ sudo tcpdump -ni eth0 'host 198.51.100.88 and tcp port 443'
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:44:10.101010 IP 198.51.100.88.50122 > 203.0.113.20.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 101 ecr 0,nop,wscale 7], length 0
12:44:10.101200 IP 203.0.113.20.443 > 198.51.100.88.50122: Flags [S.], seq 987654321, ack 1234567891, win 65160, options [mss 1460,sackOK,TS val 202 ecr 101,nop,wscale 7], length 0
Ce que cela signifie : Le serveur répond correctement sur la bonne interface. Si le client ne peut toujours pas se connecter, quelque chose entre le serveur et le client droppe les réponses (pare-feu de périmètre, ISP, protection anti-DDoS, état NAT incorrect).
Décision : Orientez votre attention vers l’extérieur : dispositif de périmètre, passerelle NAT, pare-feu cloud, ou route de retour au-delà de cet hôte.
Task 9: Catch asymmetric return routing (reply leaves the wrong interface)
cr0x@server:~$ sudo tcpdump -ni any 'host 198.51.100.88 and tcp port 443'
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
12:44:10.101010 eth0 IP 198.51.100.88.50122 > 203.0.113.20.443: Flags [S], seq 1234567890, win 64240, length 0
12:44:10.101300 eth1 IP 10.10.0.10.443 > 198.51.100.88.50122: Flags [S.], seq 987654321, ack 1234567891, win 65160, length 0
Ce que cela signifie : Le SYN est arrivé sur eth0 vers l’IP publique, mais le SYN-ACK sort depuis l’IP privée sur eth1. Le client n’acceptera jamais cela. C’est la signature d’une sélection incorrecte de l’IP source, du policy routing, ou de routes sans src.
Décision : Corrigez la sélection de l’adresse source et le routage. Correctifs typiques : définir le src correct sur les routes, ajouter un ip rule par source, ou garantir que les services DNATés répondent via la passerelle NAT.
Task 10: Validate NAT rules on a gateway (MASQUERADE/SNAT/DNAT)
cr0x@server:~$ sudo nft list table ip nat
table ip nat {
chain prerouting {
type nat hook prerouting priority -100; policy accept;
tcp dport 443 dnat to 10.10.0.10:443
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
oif "eth0" masquerade
}
}
Ce que cela signifie : Le DNAT envoie le 443 entrant vers un serveur interne. Le postrouting masquerade garantit que les réponses quittant eth0 ont une source publique. Si le masquerade manque, les hôtes internes peuvent répondre avec des adresses privées qui meurent sur Internet.
Décision : Si les clients WAN ne peuvent pas compléter la poignée de main, confirmez que le DNAT (entrant) et le SNAT/MASQUERADE (sortant) sont corrects pour le chemin.
Task 11: Confirm forwarding is enabled (only relevant on gateways/routers)
cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
Ce que cela signifie : Si ceci est une passerelle NAT et que ip_forward est à 0, vous pouvez DNATer toute la journée et rien ne sera routé. Les tests LAN peuvent encore fonctionner si vous contournez la passerelle ou atteignez les services localement.
Décision : Si vous attendez du routage/NAT via cette machine, net.ipv4.ip_forward doit être 1 et la chaîne forward doit autoriser le trafic.
Task 12: Check conntrack utilization (the “it works until peak” problem)
cr0x@server:~$ sudo conntrack -S
cpu=0 found=120 new=42 invalid=3 ignore=0 delete=8 delete_list=8 insert=42 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=1 found=115 new=38 invalid=1 ignore=0 delete=6 delete_list=6 insert=38 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cr0x@server:~$ cat /proc/sys/net/netfilter/nf_conntrack_count
51234
cr0x@server:~$ cat /proc/sys/net/netfilter/nf_conntrack_max
65536
Ce que cela signifie : Vous êtes proche du maximum. Quand la table se remplit, de nouvelles connexions tombent. Les tests LAN peuvent réussir parce qu’ils ne traversent pas le NAT/conntrack, ou parce que le chemin LAN est plus simple.
Décision : Si les compteurs approchent la limite, augmentez nf_conntrack_max, réduisez les timeouts pour les protocoles bruyants, ou arrêtez de funneler tout via une table d’état surchargée.
Task 13: Detect MTU/MSS issues (WAN stalls, small payload works)
cr0x@server:~$ ip link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
cr0x@server:~$ ping -M do -s 1472 198.51.100.1 -c 3
PING 198.51.100.1 (198.51.100.1) 1472(1500) bytes of data.
From 203.0.113.20 icmp_seq=1 Frag needed and DF set (mtu = 1492)
From 203.0.113.20 icmp_seq=2 Frag needed and DF set (mtu = 1492)
From 203.0.113.20 icmp_seq=3 Frag needed and DF set (mtu = 1492)
--- 198.51.100.1 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2031ms
Ce que cela signifie : Votre PMTU est plus petit que 1500 (commun avec PPPoE/VPN). Si ICMP est bloqué en amont, PMTUD casse et les sessions TCP peuvent se bloquer—souvent uniquement sur WAN.
Décision : Corrigez le MTU sur l’interface/tunnel, autorisez l’ICMP « Fragmentation needed », ou clampiez le MSS sur le pare-feu de bord pour TCP.
Task 14: Confirm DNS isn’t the real culprit (split-horizon, wrong A/AAAA)
cr0x@server:~$ dig +short app.example.internal A
10.10.0.10
cr0x@server:~$ dig +short app.example.internal @1.1.1.1 A
203.0.113.20
Ce que cela signifie : Le DNS interne retourne une IP privée ; le résolveur public retourne l’IP publique. C’est normal pour le split-horizon. Cela devient un problème quand des clients « WAN-mais-pas-vraiment » (utilisateurs VPN, réseaux partenaires) reçoivent la mauvaise vue.
Décision : Décidez quels clients doivent voir quelle adresse. Corrigez le forwarding conditionnel sur le DNS VPN, ou cessez d’essayer d’utiliser un seul nom pour deux mondes sauf si vous contrôlez les résolveurs.
Blague #1 : Le NAT, c’est comme la politique de bureau : tout fonctionne jusqu’à ce que quelqu’un demande qui a le droit de parler à qui.
Trois mini-récits d’entreprise tirés du terrain
Mini-récit 1 : La panne causée par une mauvaise hypothèse
Une entreprise exécutait un portail client derrière un reverse proxy basé sur Debian. En interne, tout le monde y accédait via le nom de service, qui résolvait en VIP privé. Depuis Internet, il résolvait en IP publique sur un pare-feu de bord qui forwardait le 443 vers le même reverse proxy.
Une équipe a ajouté un second uplink pour la « redondance ». Le serveur est devenu multi-homed : eth0 vers le pare-feu, eth1 vers un nouvel appareil SD-WAN. Ils ont supposé que Linux « ferait la bonne chose » et renverrait le trafic par l’interface d’entrée. Linux a fait ce que Linux fait : il route selon ses tables, pas selon les espoirs de quelqu’un.
Les tests LAN continuaient de passer parce que les clients internes touchaient le VIP privé et le trafic restait côté privé. Les tests WAN échouaient de façon intermittente. Parfois la poignée de main réussissait, parfois non, selon l’adresse source sélectionnée et la règle de routage qui dominait à ce moment.
La percée du débogage fut une capture tcpdump -ni any qui montra des SYN arrivant sur eth0 mais des SYN-ACK sortant via eth1 avec la mauvaise IP source. Une fois que l’équipe a ajouté des règles de routage basées sur la source et mis rp_filter en mode lâche sur les interfaces concernées, le chemin WAN s’est stabilisé.
La mauvaise hypothèse n’était pas « Linux est cassé ». C’était de croire que le routage symétrique est la valeur par défaut dans un monde multi-homed. Ce n’est pas le cas. Ça ne l’a jamais été.
Mini-récit 2 : L’optimisation qui s’est retournée
Une autre organisation voulait réduire la latence. Ils ont déplacé le NAT et le firewall d’un appliance dédié vers une VM Ubuntu « proche de la charge ». Ça paraissait bien dans les tests synthétiques. La VM avait du CPU en réserve, et les chiffres iperf étaient fantastiques à l’intérieur du DC.
Puis le trafic réel est arrivé : beaucoup de connexions HTTPS de courte durée depuis Internet, plus du monitoring UDP depuis des réseaux partenaires. La table conntrack s’est remplie durant les pics. Quand elle a atteint le plafond, de nouvelles connexions ont été rejetées. L’équipe applicative a ouvert un ticket : « WAN instable, LAN OK. » Le ticket était fourni avec captures d’écran et déception.
Le LAN allait bien parce que les requêtes internes ne traversaient pas ce chemin NAT ou créaient moins d’états. Le WAN était une foire à la conntrack. Ils avaient « optimisé » en compressant des rôles sans dimensionner les tables d’état, les timeouts et les paramètres noyau pour un comportement Internet.
Le correctif n’a pas été héroïque. Ils ont mesuré l’utilisation de conntrack, augmenté nf_conntrack_max, réduit les timeouts UDP spécifiques quand approprié, et ajouté une surveillance de la saturation conntrack. Surtout, ils ont cessé de considérer le NAT comme un tuyau sans état. Le NAT est de l’état, et l’état nécessite de la capacité.
Blague #2 : Rien ne dit « haute disponibilité » comme une table conntrack unique qui panique dès que le marketing lance une promo.
Mini-récit 3 : La pratique ennuyeuse qui a sauvé la mise
Une société financière avait une règle simple : chaque changement exposé sur Internet incluait une capture de paquets avant et après, stockée avec le dossier de changement. Rien de nouveau. Juste assez pour montrer le comportement d’ingress et d’egress.
Un vendredi, une petite mise à jour du pare-feu est sortie. Immédiatement, des utilisateurs distants ont signalé qu’ils pouvaient atteindre la page de connexion mais que les téléchargements de fichiers se bloquaient. Au bureau, tout fonctionnait. L’instinct premier fut de blâmer l’application ou le backend de stockage car « les téléchargements sont gros ».
L’ingénieur d’astreinte a sorti la capture « avant » de la semaine précédente et a pris une capture « après ». La nouvelle capture montrait des sessions TCP qui se bloquaient après une certaine taille de paquet. Puis ils ont vu le vrai changement : ICMP type 3 code 4 avait été bloqué « pour la sécurité ». PMTUD était cassée, et le MSS n’était pas clampé. Classique douleur WAN-only.
Ils ont rétabli le blocage ICMP, ajouté un allow explicite pour les messages ICMP nécessaires, et documenté quand utiliser le clamp MSS sur les liens VPN. L’incident a duré des minutes, pas des heures, parce qu’ils disposaient d’une base et de la discipline pour comparer. Ennuyeux, correct, reproductible. Le meilleur genre d’ops.
Citation fiabilité (idée paraphrasée) : « On ne peut pas améliorer ce que l’on ne mesure pas. » — W. Edwards Deming (idée paraphrasée)
Erreurs fréquentes : symptôme → cause racine → correction
1) « Fonctionne depuis le LAN, timeout depuis le WAN »
Symptôme : Aucune connexion depuis Internet ; les clients LAN réussissent.
Cause racine : Le trafic entrant n’atteint jamais l’hôte (mauvaise IP publique, port forward manquant, groupe de sécurité cloud bloque, ISP bloque).
Correction : Capture sur l’interface WAN. Si rien n’arrive, corrigez le NAT/pare-feu en amont. Ne touchez pas à l’application.
2) « SYN arrive, pas de SYN-ACK sortant »
Symptôme : tcpdump montre un SYN entrant, mais aucune réponse.
Cause racine : Drop par le pare-feu local, service non lié à cette IP/port, rp_filter, ou route locale vers le client cassée.
Correction : Vérifiez ss -lntup, puis les règles de pare-feu (nft), ensuite rp_filter, puis le routage.
3) « SYN-ACK sort mais le client ne complète jamais la poignée de main »
Symptôme : Le serveur répond, mais le client retransmet le SYN.
Cause racine : Chemin de retour cassé au-delà du serveur, mauvaise IP source sur la réponse (routage asymétrique), ou drops en amont.
Correction : Capture sur any pour voir l’interface de sortie de la même flow. Corrigez le policy routing ou le NAT sur la passerelle. Vérifiez les règles en amont.
4) « Les utilisateurs VPN échouent, les internautes OK »
Symptôme : Les clients VPN distants ne peuvent pas joindre le service en utilisant le nom public ; les autres le peuvent.
Cause racine : Mismatch DNS split-horizon, ou hairpin NAT non supporté sur l’egress VPN.
Correction : Corrigez la vue DNS pour le VPN, fournissez un nom/VIP interne pour les utilisateurs VPN, ou implémentez correctement le hairpin NAT.
5) « Les petites requêtes fonctionnent, gros téléchargements se bloquent »
Symptôme : La page de connexion charge, mais les transferts de fichiers se bloquent sur WAN.
Cause racine : Échec MTU/PMTUD dû au blocage d’ICMP ou surcharge de tunnel ; absence de clamp MSS.
Correction : Autorisez l’ICMP fragmentation-needed, réglez le MTU correct, clampiez le MSS côté bord pour TCP quand nécessaire.
6) « Tout casse pendant les pics, puis revient »
Symptôme : Pannes WAN aléatoires corrélées à la charge.
Cause racine : Exhaustion de la table conntrack, pénurie de ports NAT, ou saturation d’un pare-feu à états.
Correction : Mesurez le nombre conntrack vs max, ajustez limites/timeouts, scalez le NAT, ou réduisez la création d’état inutile.
7) « IPv4 WAN échoue mais IPv6 marche » (ou inverse)
Symptôme : Une famille d’adresses fonctionne ; l’autre est morte.
Cause racine : Mismatch de binding de l’app, règles de pare-feu différentes, enregistrement AAAA/A manquant ou route incorrecte pour une famille.
Correction : Vérifiez ss pour les sockets v4/v6, vérifiez les règles de pare-feu par famille, validez les enregistrements DNS par famille.
8) « Le LAN marche via IP, échoue via hostname »
Symptôme : curl https://10.10.0.10 marche mais curl https://app.example.internal échoue.
Cause racine : Le DNS pointe vers une adresse différente sur le WAN, ou le certificat/SNI route différemment sur le reverse proxy.
Correction : Comparez le DNS depuis l’intérieur et l’extérieur, vérifiez la configuration vhost du reverse proxy et le SNI, confirmez la bonne IP cible.
Listes de vérification / plan étape par étape
Checklist A: Hôte unique directement sur IP publique (pas de DNAT)
- Confirmer le socket d’écoute :
ss -lntup. S’il est lié à localhost/privé uniquement, corrigez la configuration du service. - Confirmer le pare-feu local :
nft list ruleset. Si la politique est drop, autorisez explicitement le port. - Confirmer que les paquets arrivent :
tcpdump -ni eth0pendant un test depuis le WAN. - Si les paquets arrivent mais pas de réponse : vérifier rp_filter et les routes vers le sous-réseau client.
- Si la réponse sort mais que le client ne la voit pas : engager le pare-feu/ISP en amont, vérifier le routage de retour, vérifier toute politique de scrub anti-DDoS.
- Pour « gros payloads qui se bloquent » : tester MTU/PMTUD et l’autorisation ICMP.
Checklist B: Passerelle NAT faisant du port forwarding (DNAT vers serveur privé)
- Sur la passerelle, confirmer que la règle DNAT existe et correspond à l’interface/port.
- Sur la passerelle, confirmer que la chaîne forward permet le trafic (acceptation stateful typique).
- Sur la passerelle, confirmer le SNAT/MASQUERADE pour les réponses sortant sur l’interface WAN.
- Sur le serveur interne, confirmer qu’il voit la connexion entrante (tcpdump sur l’interface privée).
- Sur le serveur interne, confirmer que sa route par défaut pointe vers la passerelle (sinon les réponses contournent le NAT et meurent).
- Surveiller conntrack sur la passerelle pendant les tests ; le NAT a besoin d’état.
Checklist C: Hôte multi-homed (deux interfaces, deux chemins)
- Capturer sur
anyet vérifier l’interface d’ingress et d’egress pour le même flux. - Vérifier
ip ruleet toutes les tables de routage utilisées. - Mettre rp_filter en mode lâche (2) là où un routage asymétrique est attendu.
- Verrouiller les adresses source en utilisant
srcsur les routes ou du policy routing par sous-réseau source. - Retester et vérifier que la réponse sort de l’uplink correct de façon cohérente.
Checklist D: Sanity DNS et hairpin (commun en bureaux et VPN)
- Comparer les réponses DNS depuis l’intérieur et l’extérieur avec
digen spécifiant les résolveurs. - Si les clients internes résolvent l’IP publique, tester si le bord supporte le hairpin NAT.
- Si le hairpin n’est pas supporté, ne le forcez pas : fournissez un nom interne/VPN conditionnel.
- Vérifier que les certificats et le routage SNI correspondent au nom d’hôte réellement utilisé par les utilisateurs.
FAQ
1) Si ça marche sur LAN, cela ne prouve-t-il pas que l’application est correcte ?
Ça prouve que l’application peut répondre sur un chemin. Le WAN ajoute du routage, du NAT et des politiques de pare-feu différentes. Traitez le succès LAN comme « l’application n’est pas complètement morte », rien de plus.
2) Quel est le test le plus rapide pour éviter de deviner ?
tcpdump sur l’interface WAN pendant une tentative de connexion depuis le WAN. Si rien n’arrive, cessez de blâmer le serveur.
3) Pourquoi rp_filter casse le WAN mais pas le LAN ?
Le trafic LAN utilise souvent un chemin symétrique simple. Le trafic WAN sur des hôtes multi-homed ou des réseaux avec policy routing peut paraître « usurpé » à rp_filter strict, donc le noyau le droppe tôt.
4) J’ai ouvert le port dans UFW mais ça échoue toujours. Pourquoi ?
Soit UFW n’est pas la couche firewall active que vous croyez, soit le trafic n’atteint pas l’hôte, soit vous faites du DNAT vers une autre machine qui bloque encore. Validez toujours les règles actives réelles avec nft list ruleset et capturez le trafic.
5) Comment savoir si j’ai du routage asymétrique ?
Capturez sur any et observez un même flux. Si le SYN entre sur une interface et que le SYN-ACK sort sur une autre, vous avez de l’asymétrie. Ensuite vérifiez ip rule et les routes par table.
6) Pourquoi les gros téléchargements échouent mais la page de connexion marche ?
C’est le motif d’échec MTU/PMTUD. Les petits paquets passent ; les plus gros nécessitent fragmentation ou signalisation PMTUD. Si l’ICMP « fragmentation needed » est bloqué, TCP se bloque.
7) L’épuisement de conntrack peut-il vraiment ressembler à « WAN only » ?
Oui. Beaucoup de chemins LAN ne traversent pas des dispositifs lourds en NAT/conntrack, ou créent moins d’états. Le trafic Internet est brusque et stateful, et il trouve très bien les limites de vos tables.
8) Nous faisons du DNAT vers un hôte interne. Pourquoi l’hôte interne a-t-il besoin de la bonne route par défaut ?
Parce que les réponses doivent repasser par la passerelle NAT pour être traduites correctement. Si l’hôte interne envoie les réponses vers une autre passerelle, le client verra des IPs sources privées ou des états incohérents et la session mourra.
9) L’IPv6 est-elle pertinente pour « LAN marche, WAN échoue » ?
Absolument. Beaucoup d’environnements exposent accidentellement IPv6 en interne mais pas en externe (ou inversement). Vérifiez les bindings, les enregistrements AAAA/A et les règles de pare-feu par famille.
10) Dois-je juste activer MASQUERADE partout ?
Non. C’est comme créer une dette de debugging et des chemins surprises. SNAT/MASQUERADE doit être précis : interface d’egress correcte, sous-réseaux source corrects, et seulement là où la traduction est réellement nécessaire.
Conclusion : prochaines étapes à faire réellement
Si vous ne retirez qu’une habitude de ceci : capturez d’abord. « Fonctionne sur LAN, échoue sur WAN » est une histoire de routage/NAT/filtrage jusqu’à preuve du contraire. Votre travail est de prouver où le paquet disparaît.
- Exécutez
tcpdumpsur l’interface WAN pendant une tentative échouée. Décidez : amont vs local. - Si c’est local, vérifiez dans l’ordre : sockets d’écoute → règles de pare-feu → rp_filter → routage/policy routing.
- Si c’est du DNAT, vérifiez les deux directions : DNAT entrant, SNAT/MASQUERADE sortant, et la route par défaut correcte sur l’hôte interne.
- Si c’est instable sous charge, mesurez conntrack et les limites des tables d’état et cessez de traiter le NAT comme gratuit.
- Si « gros payloads qui se bloquent », corrigez MTU/PMTUD et ne bloquez pas aléatoirement les ICMP sans en comprendre l’impact.
Faites cela, et « fonctionne sur LAN, échoue sur WAN » devient moins un mystère et plus une checklist avec preuves.