DNS via WireGuard : corriger les 3 pannes
Tunnel WireGuard actif, mais DNS en échec ou requêtes vers le routeur local ? Identifiez l’une des 3 pannes et corrigez le resolver et le routage.
Pourquoi le DNS cesse de fonctionner dès que le tunnel WireGuard est établi
Le DNS via WireGuard échoue de trois façons, et chacune a sa propre solution. Plus aucun nom ne se résout, ou les noms se résolvent mais les requêtes quittent votre machine en dehors du tunnel, ou le gestionnaire de résolution du client écrase le paramètre quelques secondes après le démarrage de l’interface. Le tunnel est presque toujours hors de cause. Le problème vient de la ligne qui indique au client quel resolver interroger et du routage qui détermine comment les paquets destinés à ce resolver circulent.
WireGuard transporte des paquets IP et ne connaît rien au DNS (domain name system, le service qui convertit des noms tels que example.com en adresses IP). La ligne DNS = dans un bloc client [Interface] n’est pas un paramètre WireGuard. Elle est lue par wg-quick, le shell wrapper qui active l’interface, puis wg-quick modifie la configuration du resolver du client pendant que le tunnel est actif et la restaure sur wg-quick down. Chaque problème ci-dessous relève donc du routage ou de wg-quick, jamais de la cryptographie. Si le tunnel n’est pas encore configuré, commencez par un VPN WireGuard auto-hébergé sur votre propre VPS, puis revenez sur cette page.
Vérifiez d’abord que le tunnel fonctionne correctement, avant de modifier le DNS.
sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1wg show doit répertorier le peer avec un latest handshake récent, et les deux pings doivent recevoir une réponse. Si ping 1.1.1.1 expire, vous avez un problème de forwarding ou de NAT (network address translation), et non un problème de DNS. Aucune modification de la configuration du resolver ne pourra le résoudre. Tous les exemples utilisent 10.8.0.0/24 comme sous-réseau du tunnel et 10.8.0.1 comme adresse du tunnel sur le serveur. Remplacez-les par vos propres valeurs.
Échec 1 : rien ne se résout, car le resolver ne répond jamais
Le symptôme est précis. ping 1.1.1.1 fonctionne, et curl https://example.com renvoie ceci :
curl: (6) Could not resolve host: example.comInterrogez directement le tunnel resolver depuis le client. dig provient du package dnsutils sur Ubuntu et Debian.
dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.comLa première commande renvoie une adresse, ce qui prouve que les paquets atteignent Internet via le tunnel. La seconde ne renvoie rien et affiche ;; communication timed out; no servers could be reached. Le diagnostic est donc complet : votre client utilise 10.8.0.1, et 10.8.0.1 ne répond pas sur le port UDP 53.
Deux causes sont possibles. Soit aucun resolver ne s’exécute sur le serveur, soit le pare-feu du serveur bloque la requête avant son arrivée. Vérifiez les deux points sur le serveur.
sudo ss -ulnp | grep ':53'
sudo nft list rulesetUn resolver en cours d’exécution et correctement bindé affiche une ligne contenant 10.8.0.1:53 ou 0.0.0.0:53. Sur Ubuntu, la cause est généralement 127.0.0.53:53 : il s’agit du stub listener de systemd-resolved, qui se bind sur une adresse loopback et reste volontairement inaccessible depuis les autres machines. Configurer un client VPN pour utiliser un serveur dont le seul resolver est ce stub produit exactement ce timeout.
La correction consiste à utiliser un resolver qui écoute sur l’adresse du tunnel, ainsi qu’une règle de pare-feu qui autorise les pairs à l’atteindre.
sudo apt update && sudo apt install -y unbound
printf 'server:\n interface: 10.8.0.1\n access-control: 10.8.0.0/24 allow\n' \
| sudo tee /etc/unbound/unbound.conf.d/wireguard.conf
sudo systemctl restart unbound
sudo ss -ulnp | grep '10.8.0.1:53'Ouvrez ensuite le port uniquement pour le trafic du tunnel. Avec nftables, ajoutez ces deux lignes à la chaîne input dans /etc/nftables.conf, puis rechargez avec sudo systemctl reload nftables.
udp dport 53 iifname "wg0" accept
tcp dport 53 iifname "wg0" acceptAvec ufw, sudo ufw allow in on wg0 to any port 53 effectue la même opération. N’ouvrez jamais le port 53 sur Internet. Un resolver récursif ouvert est découvert par les scanners en quelques jours et utilisé pour amplifier des attaques par déni de service. Votre fournisseur détectera ce trafic avant vous.
Relancez dig +short @10.8.0.1 example.com depuis le client. Une adresse dans la sortie signifie que le chemin vers le resolver fonctionne. Le client doit maintenant simplement l’utiliser. Ajoutez la ligne au bloc [Interface] du client, puis redémarrez l’interface avec sudo wg-quick down wg0 && sudo wg-quick up wg0.
[Interface]
PrivateKey = <client private key>
Address = 10.8.0.2/32
DNS = 10.8.0.1Échec numéro 2 : fuites DNS, car un split tunnel ne route pas le résolveur
Celui-ci est plus grave, car tout semble fonctionner. Les noms sont résolus, les pages se chargent, et les requêtes circulent en clair sur le réseau local auquel vous ne vouliez pas faire confiance.
Deux configurations en sont à l'origine. La première est un client avec AllowedIPs = 0.0.0.0/0, ::/0 et sans ligne DNS =. wg-quick installe la route par défaut dans sa propre table de routage et ajoute une règle avec suppress_prefixlength 0. Cela conserve volontairement les routes locales plus spécifiques afin que la machine puisse toujours atteindre son imprimante. Le résolveur appris par le client via DHCP, généralement le routeur à 192.168.1.1, correspond à l'une de ces routes locales. Votre trafic passe par le tunnel. Le réseau local reçoit toujours la liste complète des noms que vous recherchez.
La seconde configuration est un split tunnel : AllowedIPs = 10.8.0.0/24 avec DNS = 9.9.9.9. Comme 9.9.9.9 ne se trouve pas dans AllowedIPs, le client n'a aucune route vers cette adresse via le tunnel. La requête sort donc par la liaison locale, exactement comme dans le premier cas.
Vérifiez quel résolveur répond réellement. whoami.akamai.net est un nom de test public qui répond avec l'adresse IP du résolveur récursif ayant effectué la requête. Vous pouvez donc comparer sa réponse avec l'adresse publique de votre serveur.
resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53resolvectl status affiche un bloc par liaison. Si le bloc de votre liaison Ethernet ou sans fil affiche encore Current DNS Server: 192.168.1.1, tandis que le bloc wg0 n'en affiche aucun, il s'agit de la fuite. Si dig +short whoami.akamai.net renvoie l'adresse de votre connexion haut débit à domicile au lieu de celle de votre serveur, cela la confirme depuis l'autre extrémité. La ligne tcpdump apporte la preuve décisive : dans une configuration saine, chaque paquet destiné au port 53 passe par wg0 ; en cas de fuite, il passe par wlan0 ou enp3s0.
La correction comporte deux volets, qui sont tous deux nécessaires. Définissez DNS sur une adresse située dans le tunnel et vérifiez que cette adresse se trouve dans AllowedIPs.
[Interface]
Address = 10.8.0.2/32
DNS = 10.8.0.1
[Peer]
PublicKey = <server public key>
Endpoint = vpn.example.com:51820
AllowedIPs = 10.8.0.0/24, 10.20.0.0/1610.8.0.1 se trouve dans 10.8.0.0/24. La requête est donc chiffrée et envoyée au serveur. Si vous tenez à utiliser un résolveur public avec un split tunnel, ajoutez-le comme route d'hôte : AllowedIPs = 10.8.0.0/24, 9.9.9.9/32. Les paquets passent alors par le tunnel, mais le réseau local peut toujours voir que vous avez choisi ce fournisseur lors de sessions précédentes. Un résolveur que vous gérez vous-même évite ce problème.
L'attribution du résolveur est l'une des différences visibles entre WireGuard configuré manuellement et un mesh coordonné. Elle fait partie du compromis présenté dans WireGuard comparé à Tailscale. L'utilisation de un serveur de contrôle Headscale auto-hébergé vous apporte cette coordination sans confier votre matériel de clés à un tiers.
Échec 3 : resolvconf et systemd-resolved se disputent la configuration sur les clients Linux
Les clients macOS, Windows, iOS et Android appliquent DNS = via l’application officielle et posent rarement problème. Sous Linux, le paramètre est appliqué par un shell script qui doit déterminer lequel de plusieurs gestionnaires de résolution est utilisé.
Le premier échec est explicite. sudo wg-quick up wg0 s’arrête avec :
resolvconf: command not foundwg-quick appelle resolvconf, mais ce binaire n’est pas installé. Installez l’implémentation qui communique avec systemd-resolved, puis réactivez l’interface.
sudo apt install -y openresolv
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0Le deuxième échec est silencieux et peut vous faire perdre une soirée. L’interface est activée, resolvectl status wg0 affiche correctement DNS Servers: 10.8.0.1, mais les résolutions utilisent toujours l’ancien resolver. systemd-resolved conserve une liste de resolvers distincte pour chaque lien et sélectionne un lien pour chaque requête. Si aucun lien n’est marqué comme route par défaut pour les noms, il continue d’utiliser le resolver du lien sans fil, car ce lien possède un domaine de recherche et pas le vôtre.
Définissez le resolver et attribuez la route par défaut au même moment. %i est remplacé par le nom de l’interface ; ce bloc fonctionne donc sans modification sur n’importe quelle interface.
[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %iSupprimez la ligne DNS = lorsque vous utilisez PostUp de cette manière. Sinon, deux mécanismes écrivent l’état du resolver et un seul effectue le nettoyage ensuite. L’argument ~. est essentiel : il définit wg0 comme domaine de routage pour tous les noms. systemd-resolved envoie ainsi toutes les requêtes à cet endroit au lieu de sélectionner un lien pour chaque requête. Vérifiez la configuration.
resolvectl status wg0Une sortie correcte contient DNS Servers: 10.8.0.1 et Default Route: yes. Si Default Route contient no, la partie resolvectl domain n’a pas été exécutée et la sélection des liens est toujours utilisée.
Un autre cas mérite d’être mentionné. Si /etc/resolv.conf est un fichier réel plutôt qu’un lien symbolique vers /run/systemd/resolve/stub-resolv.conf, un autre composant le gère, généralement NetworkManager ou un runtime de conteneurs. Exécutez ls -l /etc/resolv.conf avant tout autre diagnostic, car un outil qui réécrit ce fichier à chaque changement réseau annulera votre configuration au moment le moins opportun.
La mise à niveau : votre propre resolver filtrant sur le tunnel
Une fois que les requêtes passent de manière fiable dans le tunnel, le resolver à l’autre extrémité devient un point de contrôle. En y exécutant AdGuard Home, vous fournissez à chaque appareil connecté un filtrage par blocklist et un journal des requêtes, sans logiciel client ni configuration par appareil. Le script d’installation officiel, vérifié en juillet 2026, tient sur une ligne.
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -vL’assistant de configuration écoute sur le port 3000 au premier démarrage. Accédez-y via le tunnel à l’adresse http://10.8.0.1:3000 au lieu d’ouvrir ce port publiquement. Dans l’assistant, définissez l’adresse d’écoute DNS et l’adresse d’écoute d’administration sur 10.8.0.1. Si unbound du premier échec utilise toujours la même adresse, arrêtez-le d’abord avec sudo systemctl disable --now unbound, car deux processus ne peuvent pas binder le port UDP 53 sur une même adresse et le second s’arrête avec listen udp 10.8.0.1:53: bind: address already in use.
Les configurations client ne nécessitent aucune modification si elles indiquent déjà DNS = 10.8.0.1. Le journal des requêtes affiche désormais chaque lookup de chaque peer. Il s’agit d’une véritable décision de confidentialité, pas d’un avantage gratuit : vous transférez la confiance de votre fournisseur d’accès à Internet vers vous-même, et c’est à vous de maintenir ce serveur à jour. Un serveur exposé à Internet doit d’abord disposer des mesures de base, et les dix premières minutes sur un nouveau VPS les présente.
FAQ
Pourquoi mon tunnel WireGuard se connecte-t-il, mais les noms ne sont-ils pas résolus ?
Le tunnel transporte les paquets, mais ne gère pas les noms. Si le tunnel fonctionne alors que les recherches échouent, le resolver indiqué ne répond pas. Testez avec dig +short @10.8.0.1 example.com depuis le client. Une réponse communication timed out signifie soit qu’aucun resolver n’écoute sur cette adresse du tunnel, souvent parce que le stub de systemd-resolved est lié uniquement à 127.0.0.53, soit que le firewall du serveur bloque le port UDP 53 entrant sur wg0. Corrigez d’abord l’écoute, puis ouvrez le port uniquement pour wg0.
Comment vérifier si mon DNS fuit via WireGuard ?
Exécutez sudo tcpdump -ni any -c 10 port 53 sur le client et surveillez la colonne de l’interface pendant que vous naviguez. Chaque paquet doit passer par wg0. S’ils apparaissent sur votre interface Wi-Fi ou Ethernet, les requêtes sortent en clair. dig +short whoami.akamai.net fournit une seconde vérification, car il répond avec l’adresse publique du resolver récursif qui a effectué la requête. Une réponse qui ne contient pas l’adresse de votre serveur confirme donc la fuite.
Ai-je besoin de la ligne DNS = si j’utilise un split tunnel ?
Oui. L’adresse du resolver doit également se trouver dans AllowedIPs, sinon le client n’a aucune route vers celle-ci. Avec AllowedIPs = 10.8.0.0/24, un resolver situé à 10.8.0.1 est couvert et la requête est chiffrée. Un resolver public tel que 9.9.9.9 n’est pas couvert. La requête sort donc par la liaison locale, même si la ligne DNS semble correcte.
Pourquoi resolvectl affiche-t-il le bon serveur alors que les recherches sont toujours effectuées ailleurs ?
systemd-resolved conserve une liste de resolvers par liaison et choisit une liaison pour chaque requête. Une entrée correcte sur wg0 est donc ignorée lorsqu’une autre liaison contient la route par défaut pour les noms. Ajoutez PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. au bloc [Interface] du client et supprimez la ligne DNS =. resolvectl status wg0 devrait alors afficher Default Route: yes.
Quel client dois-je corriger en premier lorsque plusieurs clients sont défaillants ?
Corrigez d’abord un client Linux, car c’est la seule plate-forme qui permet d’observer le mécanisme. resolvectl status et tcpdump indiquent quel resolver a répondu et quelle interface a transporté le paquet. Les applications mobiles et de bureau appliquent les mêmes valeurs DNS et AllowedIPs sans exposer ces détails. Une fois le client Linux corrigé, vous copiez donc une configuration déjà vérifiée.