Un full-tunnel WireGuard sans internet sur un serveur qui fait tourner Docker 28 ou plus récent, c’est souvent le sens retour qui manque : la chaîne FORWARD est en policy DROP, seule la règle -i wg0 -j ACCEPT existe, et depuis Docker 28 l’état RELATED,ESTABLISHED n’est plus accepté que pour les bridges Docker. Les paquets du PC partaient vers internet, les réponses étaient jetées par le serveur. J’avais fini par supprimer le profil full-tunnel de guerre lasse, après un audit qui avait déclaré le serveur conforme et quatre hypothèses côté client, toutes fausses.
Le symptôme : tunnel monté, internet mort
Le contexte : mon PC a deux profils WireGuard vers srv-a, déjà évoqués dans l’article sur les deux pièges de WireGuard sur Coolify. wg-srv-s est le split-tunnel du mesh (seul 10.8.0.0/24 passe dans le tunnel), wg-srv-f le full-tunnel (AllowedIPs = 0.0.0.0/0) pour le wifi d’hôtel. Ce sont deux peers distincts côté serveur, avec chacun sa paire de clés et son IP (10.8.0.2 et 10.8.0.3).
Avec wg-srv-f activé, le tunnel montait, le mesh répondait, mais plus rien d’internet.
Quatre hypothèses côté client, toutes fausses
L’audit de mai 2026 avait commencé par le serveur et conclu « côté serveur tout est OK » :
| Élément | Constat de l’audit |
|---|---|
net.ipv4.ip_forward | 1 |
iptables FORWARD | ACCEPT wg0 → *, compteur à 551+ paquets |
nat POSTROUTING | MASQUERADE sur eno1 |
| Route par défaut | via eno1 |
Rassuré par ce compteur, je suis parti côté client, avec quatre pistes : route par défaut non posée par NetworkManager (wireguard.ip4-auto-default-route), DNS du tunnel ignoré par systemd-resolved, métrique du wifi qui gagne sur celle du tunnel, et MTU. Aucune n’était la bonne.
Pourquoi le full-tunnel WireGuard perd-il le trafic de retour ?
L’audit n’avait regardé que -i wg0, le sens aller. La chaîne FORWARD de srv-a, en septembre :
-P FORWARD DROP
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-FORWARD
-A FORWARD -i wg0 -j ACCEPT <- aller : PC -> Internet, OK
<- retour : rien en -o wg0
Les réponses d’internet arrivent sur eno1 et ressortent par wg0 : elles traversent FORWARD en -o wg0. DOCKER-CT ne rend l’état RELATED,ESTABLISHED qu’aux bridges Docker (-o br-*, -o docker0), jamais à wg0, et aucune chaîne Docker ne fait de DROP explicite : les réponses retombent sur la policy DROP. Le trafic sortait, rien ne revenait.
Depuis Docker 28, l’accept global
RELATED,ESTABLISHEDdeFORWARDest devenu une série de règles par bridge : tout full-tunnel qui reposait dessus sans le savoir perd son trafic de retour.
Docker 28 a restructuré ses chaînes iptables (DOCKER-FORWARD, DOCKER-CT). srv-a est passé en Docker 29.4.2 le 6 mai 2026, quelques jours avant l’audit.
Le correctif : la règle conntrack, et le MSS dans les deux sens
Dans /etc/wireguard/wg0.conf de srv-a, le PostUp porte désormais le chemin de retour (PostDown symétrique en -D) :
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
# Chemin de retour : sans cette regle, FORWARD policy DROP jette les reponses
PostUp = iptables -A FORWARD -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eno1 -j MASQUERADE
# MSS clamping : tunnel MTU 1420 vs WAN 1500
PostUp = iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostUp = iptables -t mangle -A FORWARD -i wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
Le second problème était masqué par le premier : aucun MSS clamping. Il ne se voit qu’une fois le routage réparé, avec la signature décrite dans l’article sur le ping OK et le débit mort en full-tunnel. Le clamp est posé dans les deux sens. Tout s’applique à chaud : iptables en direct, wg syncconf pour le nouveau peer.
Mesures du 17 septembre 2026, wg-srv-f monté :
ping 8.8.8.8 17,9 ms, 0 % perte
PMTU (ping -M do) paquet 1420 OK / 1428 BLOQUE <- conforme au MTU 1420
DNS google.com -- link: wg-srv-f (pas de fuite)
curl ifconfig.me 203.0.113.10 <- sortie par srv-a
debit 10 Mo 0,69 s -> 14,6 Mo/s <- clamp MSS OK
Côté PC : importer, pas modifier
nmcli con modify ne sait pas écrire les peers WireGuard. Le chemin qui marche : un fichier au format wg-quick (Address = 10.8.0.3/32, MTU = 1420, peer cloud.example.com:51820 avec AllowedIPs = 0.0.0.0/0), importé puis ajusté :
nmcli connection import type wireguard file wg-srv-f.conf
nmcli con modify wg-srv-f connection.autoconnect no ipv4.dns-priority -10 ipv6.method disabled
autoconnect no laisse le profil activable d’un clic sans qu’il monte seul ; dns-priority -10 fait gagner le DNS du tunnel sur celui du wifi (sinon fuite DNS) ; ipv6.method disabled évite le trafic v6 hors tunnel. ⚠️ L’import active la connexion aussitôt : la redescendre si ce n’est pas le moment.
Lessons learned
- Un audit de forwarding doit vérifier les deux sens. Une règle
-i wg0dont le compteur grimpe prouve seulement que l’aller passe. - Depuis Docker 28,
RELATED,ESTABLISHEDn’est plus accepté globalement dansFORWARD. Une interface VPN doit avoir sa propre règle conntrack-o wg0. - Un bug réseau peut en cacher un second. Une fois le retour réparé, l’absence de MSS clamping a pris le relais : clamper dans les deux sens.
- NetworkManager n’écrit pas les peers WireGuard via
modify. On passe parnmcli connection importd’un fichier wg-quick, puis on règle autoconnect, DNS et IPv6.