SSD Nodes Learn 8GB RAM — $66/yr
How to do am Matt ConnorBy Matt Connor · Updated 2026-08-02

How to Fix DNS Wey No Work for WireGuard

WireGuard tunnel fit dey up while DNS still fail or leak to your router. Find the three failure modes and fix routing, resolver settings, or manager overwrite.

Why DNS dey break as soon as WireGuard tunnel come up

DNS over WireGuard fit fail for three ways, and each one get im own fix. Nothing fit resolve at all, or names resolve but the queries comot your machine outside the tunnel, or the client own resolver manager overwrite the setting some seconds after the interface start. Almost every time, the tunnel no be the problem. The problem na the one line wey tell the client which resolver e suppose ask, plus the routing wey decide how packets go reach that resolver.

WireGuard dey move IP packets and e no know anything about DNS (domain name system, the service wey dey turn names like example.com into IP addresses). The DNS = line inside client [Interface] block no be WireGuard setting. wg-quick dey read am; na the shell wrapper wey dey bring the interface up. Then wg-quick edit the client resolver configuration while the tunnel dey live, and restore am for wg-quick down. So every problem below na routing problem or wg-quick problem, never cryptography problem. If the tunnel never build yet, start with self-hosted WireGuard VPN for your own VPS and come back to this page afterwards.

Confirm say the tunnel dey healthy before you touch DNS at all.

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

wg show suppose list the peer with recent latest handshake, and both pings suppose answer. If ping 1.1.1.1 time out, you get forwarding or NAT (network address translation) problem, no be DNS problem, and resolver config no go solve am. Every example here dey use 10.8.0.0/24 as the tunnel subnet and 10.8.0.1 as the server tunnel address. Replace dem with your own values.

Problem one: nothing dey resolve because resolver no dey answer

The symptom clear. ping 1.1.1.1 dey work, but curl https://example.com dey return this:

curl: (6) Could not resolve host: example.com

Ask the tunnel resolver directly from the client. dig dey come from the dnsutils package for Ubuntu and Debian.

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

The first command dey return an address. This prove say packets dey reach the internet through the tunnel. The second one no dey return anything and e print ;; communication timed out; no servers could be reached. Na the complete diagnosis be this: your client dey point to 10.8.0.1, and 10.8.0.1 no dey answer for UDP port 53.

Two things fit cause am. Either no resolver dey run for the server, or server firewall dey drop the query before e reach there. Check both ones for the server.

sudo ss -ulnp | grep ':53'
sudo nft list ruleset

Resolver wey dey run and bind correctly go show line wey get 10.8.0.1:53 or 0.0.0.0:53. For Ubuntu, the common surprise na 127.0.0.53:53. Na the systemd-resolved stub listener be that. E dey bind a loopback address, and other machines no fit reach am by design. If VPN client point to server wey only get this stub as resolver, na this exact timeout go happen.

The fix na resolver wey dey listen on the tunnel address, plus one firewall rule wey allow peers reach am.

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'

Then open the port for tunnel traffic only. With nftables, add these two lines to the input chain inside /etc/nftables.conf, then reload with sudo systemctl reload nftables.

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

With ufw, sudo ufw allow in on wg0 to any port 53 dey do the same work. No ever open port 53 to the public internet. Scanners fit find open recursive resolver within days and use am to amplify denial of service attacks. Your provider go notice that traffic before you notice am.

Run dig +short @10.8.0.1 example.com again from the client. If output get an address, that means the resolver path dey work. So the client only need to use am now. Add the line to the client [Interface] block and restart the interface with 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

Failure two: DNS dey leak, because split tunnel no dey route resolver

This one worse, because everything look say e dey work. Names dey resolve, pages dey load, and the queries dey travel as cleartext across the local network wey you no wan trust.

Two configurations fit cause am. The first one na client wey get AllowedIPs = 0.0.0.0/0, ::/0 but no DNS = line. wg-quick installs the default route for its own routing table and adds one rule with suppress_prefixlength 0. This one deliberately keeps more specific local routes active, so the machine fit still reach its printer. The resolver wey client learn through DHCP, usually the router for 192.168.1.1, match one of those local routes. Your traffic dey pass through the tunnel. But the local network still dey receive the full list of names wey you look up.

The second one na split tunnel: AllowedIPs = 10.8.0.0/24 with DNS = 9.9.9.9. Since 9.9.9.9 no dey inside AllowedIPs, the client no get route to am through the tunnel. So the query comot through the local link exactly like for the first case.

Prove which resolver really dey answer. whoami.akamai.net na public test name wey dey answer with the IP address of the recursive resolver wey ask the question. This one let you compare the answer with your server public address.

resolvectl status
dig +short whoami.akamai.net
sudo tcpdump -ni any -c 10 port 53

resolvectl status dey print one block for each link. If the block for your ethernet or wireless link still show Current DNS Server: 192.168.1.1 while the wg0 block show none, na leak be that. If dig +short whoami.akamai.net return your home broadband address instead of your server address, e confirm the leak from the far end. The tcpdump line na the proof wey settle the matter: healthy output dey put every port 53 packet on wg0, while leak dey put dem on wlan0 or enp3s0.

The fix get two parts, and you need both. Set DNS to an address wey dey inside the tunnel, and make sure that address dey inside 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 dey inside 10.8.0.0/24, so the query dey encrypted and sent to the server. If you insist on using a public resolver with split tunnel, add am as a host route: AllowedIPs = 10.8.0.0/24, 9.9.9.9/32. The packets go pass through the tunnel, but the local network fit still see say you choose that provider from earlier sessions. Resolver wey you run yourself avoids the issue.

Resolver assignment na one visible difference between hand-built WireGuard and coordinated mesh. This one na part of the tradeoff for WireGuard compared with Tailscale. If you run self-hosted Headscale control server, you get that coordination without giving your key material to a third party.

Failure three: resolvconf and systemd-resolved dey fight for Linux clients

macOS, Windows, iOS and Android clients dey apply DNS = through the official app and dem dey cause small wahala. Na Linux get the problem, because na shell script dey apply the setting and e gats guess which one among different resolver managers you dey run.

The first failure dey loud. sudo wg-quick up wg0 stops with:

resolvconf: command not found

wg-quick dey call resolvconf, but that binary no dey installed. Install the implementation wey dey talk to systemd-resolved, then bring the interface up again.

sudo apt install -y openresolv
sudo systemctl restart systemd-resolved
sudo wg-quick down wg0 && sudo wg-quick up wg0
resolvectl status wg0

The second failure quiet, and na this one fit waste one evening. The interface comes up, resolvectl status wg0 correctly shows DNS Servers: 10.8.0.1, but lookups still dey go to the old resolver. systemd-resolved keeps separate resolver list for each link and e dey choose one link for each query. Unless you mark one link as the default route for names, e go continue to use the wireless link resolver, because that link get search domain and your own one no get.

Set the resolver and claim the default route for the same step. %i expands to the interface name, so this block go work unchanged for any interface.

[Interface]
Address = 10.8.0.2/32
PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~.
PostDown = resolvectl revert %i

Delete the DNS = line when you use PostUp this way, because otherwise two mechanisms go write resolver state and only one go clean up afterwards. The ~. argument na the important part: e marks wg0 as the routing domain for every name, so systemd-resolved sends all queries there instead of choosing link for each query. Verify am.

resolvectl status wg0

Healthy output get DNS Servers: 10.8.0.1 and Default Route: yes. If Default Route reads no, the resolvectl domain part no run, and you don return to link selection.

One more case dey worth mentioning. If /etc/resolv.conf na real file instead of symlink to /run/systemd/resolve/stub-resolv.conf, another thing dey own am, usually NetworkManager or a container runtime. Run ls -l /etc/resolv.conf before you debug anything else, because any tool wey rewrites that file whenever network change happens go undo your work at the worst time.

Di upgrade: your own filtering resolver ova di tunnel

Once queries dey reliably pass through di tunnel, di resolver for di far end become control point. If you run AdGuard Home there, every connected device go get blocklist filtering and query log, without client software or per-device configuration. Di official install script, wey dem check for July 2026, na one line.

curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

Di setup wizard dey listen on port 3000 for di first run. Reach am through di tunnel for http://10.8.0.1:3000 instead of opening dat port publicly, then for di wizard set both di DNS listen address and di admin listen address to 10.8.0.1. If unbound from failure one still dey hold di same address, stop am first with sudo systemctl disable --now unbound, because two processes no fit bind UDP port 53 for one address and di second one go exit with listen udp 10.8.0.1:53: bind: address already in use.

Client configs no need change if dem already talk say DNS = 10.8.0.1. Di query log go now show every lookup from every peer. Dis na serious privacy decision, no be free benefit: you move trust from your internet provider to yourself, and na you go need keep dat box patched. Server wey internet expose need di basic protections in place first, and di first ten minutes for a new VPS cover dem.

FAQ

Why WireGuard tunnel connect but names no resolve?

Tunnel dey carry packets, but e no handle names at all. So if tunnel dey work but lookups dey fail, resolver wey you point to no dey answer. Test am with dig +short @10.8.0.1 example.com from the client. communication timed out reply mean say either no resolver dey listen on that tunnel address, often because systemd-resolved stub only bind to 127.0.0.53, or server firewall dey drop UDP port 53 wey enter through wg0. Fix the listener first, then open the port for wg0 only.

How I fit check whether my DNS dey leak through WireGuard?

Run sudo tcpdump -ni any -c 10 port 53 for the client and monitor the interface column while you browse. Every packet suppose dey on wg0. If dem show for your wireless or ethernet interface, the queries dey leave as cleartext. dig +short whoami.akamai.net dey give another confirmation, because e answer with the public address of the recursive resolver wey ask. So if the answer no be your server address, e confirm say leak dey happen.

I need DNS = line if I use split tunnel?

Yes. The resolver address must also dey inside AllowedIPs, otherwise client no get route to am. With AllowedIPs = 10.8.0.0/24, resolver for 10.8.0.1 dey covered and query dey encrypted. Public resolver like 9.9.9.9 no dey covered, so query go leave through local link even though DNS line look correct.

Why resolvectl dey show the correct server but lookups still dey go elsewhere?

systemd-resolved dey keep one resolver list for each link and e choose one link for each query. So correct entry for wg0 dey ignored while another link get the default route for names. Add PostUp = resolvectl dns %i 10.8.0.1; resolvectl domain %i ~. to client [Interface] block and remove DNS = line. resolvectl status wg0 suppose then report Default Route: yes.

Which client I suppose fix first when several ones dey broken?

Fix one Linux client, because na the only platform wey go show you how the mechanism work. resolvectl status and tcpdump tell you which resolver answer and which interface carry the packet. Phone and desktop apps dey apply the same DNS and AllowedIPs values without visible plumbing. So once the Linux client correct, you dey copy configuration wey you don already prove.