SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-28

Corriger les erreurs DNS avec WireGuard

Votre tunnel WireGuard est actif, mais le DNS échoue ou fuit vers le routeur local. Identifiez les trois pannes et appliquez le correctif adapté.

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 son propre correctif. Plus rien ne se résout, ou les noms se résolvent mais les requêtes quittent votre machine sans passer par le tunnel, ou le propre gestionnaire de résolution du client écrase le paramètre quelques secondes après le démarrage de l’interface. Le tunnel n’est presque jamais en cause. Le problème vient de la ligne qui indique au client quel resolver interroger et du routage qui détermine comment les paquets se rendent jusqu’à ce resolver.

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 démarre 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 toucher au DNS.

sudo wg show
ping -c 3 10.8.0.1
ping -c 3 1.1.1.1

wg show doit afficher 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), pas un problème de DNS, et aucune configuration de resolver ne vous aidera. Si les pings reçoivent une réponse mais que le débit s’effondre dès que le trafic réel commence, il s’agit d’un problème distinct : un WireGuard lent est presque toujours lié au MTU, et non à un élément traité sur cette page. 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 ces valeurs par les vôtres.

É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.com

Interrogez directement le resolver du tunnel depuis le client. dig provient du paquet dnsutils sur Ubuntu et Debian.

dig +short @1.1.1.1 example.com
dig +short @10.8.0.1 example.com

La première commande renvoie une adresse, ce qui prouve que les paquets sortent vers Internet par le tunnel. La seconde ne renvoie rien et affiche ;; communication timed out; no servers could be reached. Le diagnostic est 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 fonctionne sur le serveur, soit le firewall 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 ruleset

Un resolver actif et correctement lié affiche une ligne contenant 10.8.0.1:53 ou 0.0.0.0:53. Sur Ubuntu, la surprise vient généralement de 127.0.0.53:53 : il s’agit du stub listener de systemd-resolved, qui se lie à 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 et à ajouter une règle de firewall autorisant 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 la configuration avec sudo systemctl reload nftables.

udp dport 53 iifname "wg0" accept
tcp dport 53 iifname "wg0" accept

Avec ufw, sudo ufw allow in on wg0 to any port 53 remplit le même rôle. N’ouvrez jamais le port 53 sur Internet. Un resolver récursif ouvert est repéré par les scanners en quelques jours et utilisé pour amplifier des attaques par déni de service. Votre fournisseur remarquera 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 2 : fuites DNS, car un split tunnel n’achemine pas le resolver

Ce problème 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 la cause. La première concerne 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. Cette règle conserve volontairement les routes locales plus spécifiques afin que la machine puisse toujours joindre son imprimante. Le resolver 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 ne dispose d’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 resolver répond réellement. whoami.akamai.net est un nom de test public qui renvoie l’adresse IP du resolver récursif à l’origine de 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 53

resolvectl 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 accès haut débit domestique au lieu de celle de votre serveur, cela la confirme depuis l’extérieur. La ligne tcpdump apporte la preuve définitive : avec une configuration correcte, chaque paquet destiné au port 53 passe par wg0 ; en cas de fuite, il passe par wlan0 ou enp3s0.

Le correctif comporte deux volets, et les deux sont nécessaires. Définissez DNS sur une adresse située dans le tunnel et vérifiez que cette adresse appartient bien à 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/16

10.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 utilisez malgré tout un resolver 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 en se basant sur les sessions précédentes. Un resolver que vous hébergez vous-même évite ce problème.

L’attribution du resolver est l’une des différences visibles entre un 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 vos clés cryptographiques à un tiers. Si c’est cette dernière phrase qui vous préoccupe, retenez que Tailscale ne détient jamais les clés qui chiffrent votre trafic. La vraie question est plutôt de savoir ce qu’un serveur de coordination compromis ou un compte d’identité volé pourrait ajouter à votre réseau.

É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 réglage est appliqué par un script shell qui doit déterminer lequel de plusieurs gestionnaires de résolution DNS est utilisé.

Le premier échec est explicite. sudo wg-quick up wg0 s’arrête avec :

resolvconf: command not found

wg-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 wg0

Le deuxième échec est silencieux. C’est celui qui 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 requêtes utilisent toujours l’ancien résolveur. systemd-resolved conserve une liste de résolveurs distincte pour chaque liaison et choisit une liaison pour chaque requête. Si aucune liaison n’est marquée comme route par défaut pour les noms, il continue d’utiliser le résolveur de la liaison sans fil, car celle-ci possède un domaine de recherche et pas la vôtre.

Définissez le résolveur et revendiquez la route par défaut dans la même étape. %i est remplacé par le nom de l’interface. Ce bloc fonctionne donc sans modification avec 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 %i

Supprimez la ligne DNS = lorsque vous utilisez PostUp de cette manière. Sinon, deux mécanismes modifient l’état du résolveur, mais un seul effectue le nettoyage. L’argument ~. est la partie importante : il définit wg0 comme domaine de routage pour tous les noms. systemd-resolved y envoie donc toutes les requêtes au lieu de choisir une liaison pour chaque requête. Vérifiez le résultat.

resolvectl status wg0

Une sortie correcte contient DNS Servers: 10.8.0.1 et Default Route: yes. Si Default Route affiche no, la partie resolvectl domain n’a pas été exécutée et la sélection par liaison est de nouveau utilisée.

Un dernier 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 toute autre opération de diagnostic, car un outil qui réécrit ce fichier à chaque changement réseau annulera vos modifications au moment le moins opportun.

Le déploiement : votre propre résolveur filtrant dans le tunnel

Une fois que les requêtes circulent de manière fiable dans le tunnel, le résolveur situé à l’autre extrémité devient un point de contrôle. AdGuard Home y fournit à tous les appareils connectés un filtrage par listes de blocage 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 -- -v

L’assistant de configuration écoute sur le port 3000 lors du premier démarrage. Accédez-y via le tunnel à l’adresse http://10.8.0.1:3000 au lieu d’exposer ce port publiquement, puis définissez dans l’assistant l’adresse d’écoute DNS et l’adresse d’écoute d’administration sur 10.8.0.1. Si unbound du premier incident utilise toujours la même adresse, arrêtez-le d’abord avec sudo systemctl disable --now unbound, car deux processus ne peuvent pas écouter sur le port UDP 53 d’une même adresse et le second se termine avec listen udp 10.8.0.1:53: bind: address already in use.

Aucune modification n’est nécessaire dans les configurations des clients si elles indiquent déjà DNS = 10.8.0.1. Le journal des requêtes affichera désormais chaque résolution effectuée par chaque pair. Il s’agit d’un véritable choix 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 protections 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. Un tunnel fonctionnel avec des recherches DNS défaillantes signifie donc que 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 pare-feu du serveur bloque le port UDP 53 arrivant sur wg0. Corrigez d’abord l’écoute, puis ouvrez le port uniquement pour wg0.

Comment vérifier si mon DNS fuit par 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 cette adresse. 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 partent toujours 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 porte 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 plateforme qui montre 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 afficher le fonctionnement interne. Une fois le client Linux corrigé, vous recopiez donc une configuration que vous avez déjà vérifiée.