Gluetun avec une config WireGuard personnalisée
Traduire un fichier .conf WireGuard en variables Gluetun en mode custom : clés, endpoint IP, AllowedIPs, DNS, et les champs du .conf qui n'ont aucun équivalent.
Ce que le mode custom de Gluetun attend de vous
Gluetun accepte une configuration WireGuard personnalisée avec deux variables : VPN_SERVICE_PROVIDER=custom et VPN_TYPE=wireguard. À partir de là, vous ne choisissez plus un pays dans une liste intégrée, vous recopiez le contenu d'un fichier .conf champ par champ dans l'environnement du conteneur. C'est le chemin obligatoire pour un fournisseur absent de la liste de Gluetun, et pour un serveur WireGuard que vous faites tourner vous-même sur un second VPS.
Le reste ne change pas. Gluetun monte l'interface, pose ses règles de pare-feu et sert un résolveur DNS local aux conteneurs qui partagent sa pile réseau, exactement comme quand vous faites passer le trafic d'un conteneur par Gluetun avec un fournisseur reconnu.
Tous les noms de variables de ce guide sont vérifiés contre le tag v3.41.3 de l'image qmcgaw/gluetun, publié le 30 juillet 2026 et toujours la dernière version publiée au 27 septembre 2026. Le jeu de variables a bougé d'une version à l'autre, donc un nom lu dans un guide plus ancien n'est pas forcément celui à écrire aujourd'hui.
Le fichier .conf WireGuard, champ par champ
Voici un .conf client typique, celui que votre fournisseur vous envoie ou celui que vous écrivez pour votre propre serveur.
[Interface]
PrivateKey = cOEI9rqqbDwnN8/Bpp22sVz48T71vJ4fYmFWujulwUU=
Address = 10.8.0.5/32
DNS = 10.8.0.1
MTU = 1380
[Peer]
PublicKey = wAUaJMhAq3NFutLHIdF8AN0B5WG8RndfQKLPTEDHal0=
PresharedKey = xOEI9rqqbDwnN8/Bpp22sVz48T71vJ4fYmFWujulwUU=
Endpoint = 203.0.113.9:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25La traduction, ligne par ligne :
PrivateKeydu bloc[Interface]devientWIREGUARD_PRIVATE_KEY. C'est la clé privée du client, donc celle de la machine qui fait tourner Gluetun.AddressdevientWIREGUARD_ADDRESSES, au pluriel, masque compris. L'ancien nomWIREGUARD_ADDRESSest encore accepté dansv3.41.3.MTUdevientWIREGUARD_MTU.PublicKeydu bloc[Peer]devientWIREGUARD_PUBLIC_KEY. C'est la clé publique du serveur, pas la vôtre.PresharedKeydevientWIREGUARD_PRESHARED_KEY, et reste optionnel.Endpointse coupe en deux :WIREGUARD_ENDPOINT_IPetWIREGUARD_ENDPOINT_PORT.AllowedIPsdevientWIREGUARD_ALLOWED_IPS, en liste séparée par des virgules. Le wiki du projet donne0.0.0.0/0,::/0comme valeur par défaut.PersistentKeepalive = 25devientWIREGUARD_PERSISTENT_KEEPALIVE_INTERVAL=25s, avec l'unité, parce que Gluetun lit une durée et non un nombre de secondes.- Le nom de l'interface se règle avec
VPN_INTERFACE(ancien nom :WIREGUARD_INTERFACE), et l'implémentation avecWIREGUARD_IMPLEMENTATION, qui accepteauto,kernelspaceouuserspace.
AllowedIPs garde le sens qu'il a dans WireGuard : c'est la table de routage sortante du tunnel, et la liste des adresses sources acceptées en entrée. Si ce double rôle ne vous est pas familier, le routage par clé cryptographique est ce qu'il faut lire avant de réduire cette liste.
L'Endpoint doit être une adresse IP
WIREGUARD_ENDPOINT_IP est analysé comme une adresse IP dans v3.41.3, et la documentation upstream le dit aussi : les noms de domaine ne sont pas pris en charge. Un Endpoint = vpn.exemple.fr:51820 se résout donc à la main, avant de lancer le conteneur.
getent hosts vpn.exemple.frLa première colonne de la sortie est l'adresse à mettre dans la variable. Gardez en tête ce que cela implique : si le fournisseur change l'IP derrière ce nom, votre conteneur continue de composer l'ancienne adresse et le tunnel ne remonte plus. Rien ne vous prévient, il faut relire la valeur.
Les champs du .conf qui n'ont aucun équivalent
Certaines lignes d'un .conf ne se traduisent pas, parce qu'elles appartiennent à wg-quick et que Gluetun ne lance pas wg-quick.
DNS =du bloc[Interface]: aucune variable ne le reprend. Gluetun gère le DNS avec ses propres réglages, décrits plus bas.PostUp,PreUp,PostDown,PreDown: aucun équivalent. Un script à exécuter après la montée du tunnel se place dans votre propre conteneur.Table,FwMark,SaveConfig, et unListenPortcôté client : aucun équivalent non plus.- Plusieurs blocs
[Peer]: les variables ne portent qu'un seul couple endpoint plus clé publique. Un.confà plusieurs peers se découpe en plusieurs conteneurs Gluetun, un par peer. - Une
AddressIPv6 tient dansWIREGUARD_ADDRESSES, qui accepte une liste, mais la sortie IPv6 dépend de votre hôte Docker. Testez-la avant d'y compter.
Le docker-compose, épinglé sur une version
services:
gluetun:
image: qmcgaw/gluetun:v3.41.3
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- VPN_SERVICE_PROVIDER=custom
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${WG_PRIVATE_KEY}
- WIREGUARD_PUBLIC_KEY=${WG_SERVER_PUBLIC_KEY}
- WIREGUARD_PRESHARED_KEY=${WG_PRESHARED_KEY}
- WIREGUARD_ADDRESSES=10.8.0.5/32
- WIREGUARD_ENDPOINT_IP=203.0.113.9
- WIREGUARD_ENDPOINT_PORT=51820
- WIREGUARD_ALLOWED_IPS=0.0.0.0/0,::/0
- TZ=Europe/Paris
ports:
# le port de l'interface web du conteneur qui partagera ce reseau
- 8080:8080
restart: unless-stoppedDeux points sur ce fichier. cap_add: NET_ADMIN et le device /dev/net/tun ne sont pas décoratifs : sans eux, Gluetun ne peut pas créer d'interface et s'arrête au démarrage. Et image: qmcgaw/gluetun:v3.41.3 plutôt que :latest, parce que les noms de variables écrits ici sont ceux de ce tag. Une image qui se met à jour toute seule un mardi soir produit exactement la panne que personne ne sait diagnostiquer le lendemain.
Le conteneur applicatif rejoint ensuite cette pile réseau avec network_mode: "service:gluetun", sans publier de port lui-même. Les clés, elles, n'ont rien à faire dans le fichier compose, qui finit souvent dans un dépôt Git : mettez-les dans un .env à côté, comme décrit dans la gestion des fichiers .env et des secrets avec Compose.
Vérifier que le tunnel fonctionne vraiment
WireGuard est un protocole silencieux, et Gluetun le dit lui-même. Cette ligne du tag v3.41.3 est la plus trompeuse du lot :
Wireguard setup is complete. Note Wireguard is a silent protocol and it may or may not work, without giving any error message. Typically i/o timeout errors indicate the Wireguard connection is not working.Elle ne veut pas dire « connecté ». Elle veut dire que l'interface est montée et que les clés sont chargées. Une clé publique de serveur erronée produit exactement cette ligne, suivie de rien du tout.
La preuve de connexion est ailleurs dans les logs. Gluetun interroge un service d'adresse IP publique après la montée du tunnel, puis imprime une ligne qui commence par Public IP address is et contient l'IP, le pays et la ville. Si cette adresse est celle de votre serveur VPN et non celle de votre VPS, le tunnel porte bien le trafic.
docker compose up -d
docker compose logs -f gluetunDeuxième vérification, depuis un conteneur jetable qui partage la pile réseau de Gluetun :
docker run --rm --network=container:gluetun curlimages/curl:8.11.1 -s https://ipinfo.io/ip
curl -s https://ipinfo.io/ipLa première commande sort par le tunnel, la seconde par votre VPS. Les deux adresses doivent différer. Si elles sont identiques, le trafic ne passe pas par WireGuard. Ces commandes se lancent chez vous, sur une machine avec un device TUN et une vraie sortie VPN : les logs de votre conteneur restent la source de vérité, avant ce guide et avant n'importe quel autre.
Quand le tunnel ne porte rien, le contrôle de santé de Gluetun le remarque et relance la connexion. Le wiki du projet documente la ligne d'avertissement correspondante :
WARN [vpn] restarting VPN because it failed to pass the healthcheck: startup check: dialing: dial tcp4: lookup cloudflare.com: i/o timeoutDes lignes Connecting to qui se répètent toutes les quelques dizaines de secondes veulent dire cela : l'interface monte, et rien ne revient. En mode custom, la liste des causes est courte. Les deux clés sont croisées, l'IP ou le port d'endpoint est faux, ou votre serveur ne connaît pas ce peer.
DNS : ce que Gluetun met à la place de votre ligne DNS
Le DNS = de votre .conf est ignoré, donc il faut savoir ce qui le remplace. Dans le tag v3.41.3, le code de configuration lit DNS_SERVER (l'ancien nom DOT est toujours accepté) et l'active par défaut, avec DNS_UPSTREAM_RESOLVER_TYPE sur dot et DNS_UPSTREAM_RESOLVERS sur cloudflare. En clair : un résolveur local dans le conteneur, qui parle en DNS-over-TLS (DNS chiffré au-dessus de TLS, transport layer security) à Cloudflare, à travers le tunnel.
Ne me croyez pas sur parole pour votre installation. Gluetun imprime au démarrage l'arbre complet des réglages retenus, section par section. Lisez la section DNS de vos propres logs : c'est la seule source qui parle de votre tag et de votre fichier compose.
Pour envoyer les requêtes au résolveur de votre serveur WireGuard, 10.8.0.1 dans l'exemple, c'est DNS_ADDRESS qu'il faut regarder. Sa valeur par défaut est 127.0.0.1, c'est-à-dire le serveur local de Gluetun, donc vérifiez dans l'arbre des réglages ce que votre valeur a réellement produit. Les symptômes d'un DNS qui fuit ou qui ne répond plus sont les mêmes que sur un tunnel classique, et le diagnostic du DNS au-dessus de WireGuard s'applique tel quel.
Router à travers votre propre serveur WireGuard
Le cas le plus courant ici n'est pas un fournisseur commercial : c'est un second VPS que vous administrez. Le mapping est le même, avec une différence de vocabulaire. Votre serveur ne vous remet pas de .conf, il a un bloc [Peer] dans son wg0.conf et une clé publique.
WIREGUARD_PUBLIC_KEYreçoit la clé publique du serveur, celle produite parwg pubkey < /etc/wireguard/server.key.WIREGUARD_PRIVATE_KEYreçoit la clé privée que vous générez pour ce conteneur Gluetun, et pour lui seul.WIREGUARD_ADDRESSESreçoit l'adresse de tunnel que vous réservez à ce peer, en/32.WIREGUARD_ENDPOINT_IPetWIREGUARD_ENDPOINT_PORTreçoivent l'IP publique du VPS serveur et son port d'écoute.
Côté serveur, le bloc à ajouter tient en trois lignes :
[Peer]
PublicKey = <cle publique du conteneur Gluetun>
AllowedIPs = 10.8.0.5/32Un /32 côté serveur, parce que de ce côté AllowedIPs est une liste de contrôle d'accès : un paquet déchiffré dont l'adresse source n'est pas dans cette liste est jeté. Deux peers qui portent la même adresse de tunnel se volent le trafic sans le moindre message d'erreur, et le premier cesse simplement de recevoir. Le montage complet du serveur est décrit dans héberger votre propre serveur WireGuard sur un VPS, et ce peer s'ajoute sans couper les sessions en cours si vous suivez l'ajout d'un peer WireGuard sans redémarrer l'interface.
Le tunnel monte, les grosses pages bloquent
Un tunnel qui laisse passer ping et SSH mais reste bloqué sur les pages lourdes est un problème de MTU (maximum transmission unit, la taille maximale d'un paquet). WireGuard ajoute son en-tête, donc les paquets pleins sortent trop gros, et un équipement du chemin les jette sans renvoyer de message ICMP exploitable.
WIREGUARD_MTU est la variable qui corrige cela. Le wiki documente une valeur maximale de 1440 et ne promet pas de valeur par défaut stable, donc lisez d'abord celle que Gluetun a retenue dans l'arbre des réglages, puis descendez par paliers si le symptôme persiste. La méthode propre, qui évite de deviner des nombres ronds, est dans la recherche du vrai MTU du chemin et le clamp du MSS TCP.
Pourquoi les noms de variables ne collent pas toujours à la doc
Le wiki de Gluetun suit la branche de développement, pas votre tag. L'écart est mesurable : le wiki documente WIREGUARD_GSO, et cette variable n'apparaît nulle part dans le code de configuration de v3.41.3. Dans l'autre sens, v3.41.3 accepte encore d'anciens noms comme VPN_ENDPOINT_IP pour WIREGUARD_ENDPOINT_IP, ou DOT pour DNS_SERVER. Voilà pourquoi deux guides trouvés le même jour se contredisent sur le nom d'une même variable.
Deux habitudes suffisent à s'en sortir. Épinglez un tag dans le fichier compose. Puis relisez l'arbre des réglages imprimé au démarrage : une variable mal orthographiée n'y apparaît pas, et la faute se voit tout de suite au lieu d'attendre la première coupure.
Ce qui casse juste après
Deux choses cassent ensuite, et chacune a son guide. La première est le kill switch : le pare-feu de Gluetun bloque tout ce qui ne sort pas par le tunnel, ce qui est le comportement voulu, jusqu'au jour où le conteneur redémarre en boucle et emporte vos services avec lui. Voir le comportement du kill switch quand le VPN tombe.
La seconde est l'accès à l'interface web du conteneur placé derrière Gluetun. Son port se publie sur le conteneur Gluetun, jamais sur le conteneur applicatif, et une requête venue de votre réseau local arrive comme du trafic entrant hors tunnel. Les règles exactes, avec FIREWALL_INPUT_PORTS et FIREWALL_OUTBOUND_SUBNETS, sont dans comment joindre l'hôte et les autres conteneurs depuis Gluetun.
Ce que le mode custom vous met sur le dos
Le mode custom vous rend le contrôle, et avec lui deux corvées que les fournisseurs intégrés assuraient pour vous.
Le choix du serveur d'abord. Il n'y a plus de liste à filtrer par pays, ni de rotation automatique quand un serveur devient mauvais : une IP fixe dans WIREGUARD_ENDPOINT_IP, que vous changez à la main quand elle tombe ou quand elle est bloquée. Prévoyez de la relire après chaque incident chez votre fournisseur.
La rotation des clés ensuite. La paire de clés du conteneur ne tourne pas d'elle-même, et rien dans WireGuard n'expire : une clé privée poussée par erreur dans un dépôt reste valable jusqu'à ce que vous retiriez le peer du serveur. Notez quelque part quel conteneur porte quelle clé et quelle adresse de tunnel, sinon la question « puis-je supprimer ce peer » devient impossible à trancher passé une dizaine de peers.
La redirection de port entrante, enfin. En mode custom, il n'y a pas d'API de fournisseur à interroger : le port s'ouvre sur votre serveur WireGuard, se route vers l'adresse de tunnel du conteneur, et s'autorise avec FIREWALL_VPN_INPUT_PORTS du côté Gluetun. Le mécanisme côté fournisseur, pour comparaison, est détaillé dans le fonctionnement de la redirection de port dans Gluetun.
FAQ
Gluetun refuse mon Endpoint qui est un nom de domaine. Que faire ?
WIREGUARD_ENDPOINT_IP attend une adresse IP dans v3.41.3, et la documentation upstream précise que les noms de domaine ne sont pas pris en charge. Résolvez le nom vous-même avec getent hosts vpn.exemple.fr, mettez l'adresse obtenue dans la variable, et notez qu'il faudra la corriger si le fournisseur la change. Un nom d'hôte laissé dans cette variable fait échouer la lecture de la configuration au démarrage, avant même la montée du tunnel.
Les logs disent « Wireguard setup is complete » mais rien ne sort. Pourquoi ?
Parce que cette ligne annonce seulement que l'interface est montée et les clés chargées. Le message lui-même prévient que WireGuard est un protocole silencieux et que des erreurs i/o timeout signalent une connexion qui ne fonctionne pas. Cherchez plutôt la ligne qui commence par Public IP address is : si elle manque, ou si elle montre l'IP de votre VPS, vérifiez que WIREGUARD_PUBLIC_KEY contient la clé publique du serveur et non la vôtre, puis l'IP et le port d'endpoint.
Où passe le champ DNS = de mon fichier .conf ?
Nulle part : aucune variable Gluetun ne le reprend. Gluetun fournit son propre résolveur, activé par défaut dans v3.41.3 d'après son code de configuration, en DNS-over-TLS vers Cloudflare. Pour utiliser à la place le résolveur de votre serveur WireGuard, regardez DNS_ADDRESS, puis relisez la section DNS de l'arbre des réglages que Gluetun imprime au démarrage pour voir ce que votre valeur a produit.
Faut-il épingler une version de l'image Gluetun ?
Oui, et c'est encore plus vrai en mode custom. Le jeu de variables a changé entre versions : des noms comme VPN_ENDPOINT_IP ou DOT ne sont plus que d'anciens noms acceptés, et le wiki documente des variables absentes du dernier tag publié. qmcgaw/gluetun:v3.41.3 vous donne une configuration qui ne bouge pas tant que vous ne décidez pas de la faire bouger.
Puis-je mettre plusieurs serveurs dans un seul conteneur Gluetun en mode custom ?
Non. Les variables ne portent qu'un couple endpoint plus clé publique, donc un .conf à plusieurs blocs [Peer] se découpe en autant de conteneurs Gluetun. Chaque conteneur reçoit sa propre paire de clés et sa propre adresse de tunnel, et chaque conteneur applicatif choisit sa sortie avec network_mode: "container:<nom>".