Aller au contenu
Sylvain Joffraud l4w
Retour

WireGuard full-tunnel : Docker 28 bloque le retour

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émentConstat de l’audit
net.ipv4.ip_forward1
iptables FORWARDACCEPT wg0 → *, compteur à 551+ paquets
nat POSTROUTINGMASQUERADE sur eno1
Route par défautvia 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,ESTABLISHED de FORWARD est 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

Questions fréquentes

Pourquoi mon full-tunnel WireGuard monte mais n’a pas accès à internet ?
Sur un serveur qui fait tourner Docker, la chaîne FORWARD est souvent en policy DROP. Si seule la règle -i wg0 -j ACCEPT existe, les paquets du client sortent vers internet mais les réponses, qui reviennent en -o wg0, sont jetées. Le tunnel est up, le handshake passe, le ping vers la passerelle répond, mais rien ne revient d’internet.
Qu’est-ce que Docker 28 a changé dans les règles iptables FORWARD ?
Docker 28 a restructuré ses chaînes iptables avec DOCKER-FORWARD et DOCKER-CT. L’ancienne règle globale -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT dans FORWARD est devenue une série de règles par bridge Docker (br-*, docker0). Une interface WireGuard ne bénéficie plus de cet accept implicite du trafic de retour.
Quelle règle iptables ajouter pour le trafic retour d’un VPN WireGuard ?
Il faut autoriser explicitement le sens retour dans FORWARD : iptables -A FORWARD -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT. Placée dans le PostUp de wg0.conf (avec son symétrique en -D dans PostDown), elle est rejouée à chaque wg-quick up et profite à tous les clients full-tunnel.
Comment ajouter un profil WireGuard avec un peer dans NetworkManager ?
nmcli con modify ne sait pas écrire les peers WireGuard. Il faut écrire un fichier au format wg-quick puis l’importer avec nmcli connection import type wireguard file wg-srv-f.conf. L’import active la connexion aussitôt : la redescendre si besoin, puis régler connection.autoconnect no, ipv4.dns-priority -10 et ipv6.method disabled.

Partager cet article :

Article précédent
Enums TypeScript et PostgreSQL : un test de parité sans base
Article suivant
Prisma `not` et NULL : le filtre qui exclut presque tout