How to Test and Fix DNS Leaks on Linux
Linux has several layers that decide where DNS questions go. Learn to test which one is answering while your VPN is up, and how to fix it on systemd-resolved, NetworkManager and plain resolv.conf.
9 min readUpdated Oct 15, 2026By XPASS Editorial Team

A Linux VPN DNS leak is one of the most common reasons a connection that looks perfectly healthy is still telling your local network which sites you visit. The tunnel is up, ip addr shows the VPN interface, your public address has changed, and yet the cafe router, the hotel gateway or your internet provider is still answering your DNS questions. On Linux this happens because there is no single place that "does DNS". Several components cooperate, and any one of them can keep using the old resolver.
This article is a hands-on guide for desktop and server users. It shows how to find out which layer is answering, how to prove it on the wire, and how to fix it on the three setups you will meet most often: systemd-resolved, NetworkManager and a plain /etc/resolv.conf. If you want the general idea first, read what a DNS leak is and how DNS works.
Why Linux is easy to get wrong
On Windows and macOS the operating system has one main resolver service. On Linux, the answer depends on the distribution and on how the network is configured. A typical desktop has these layers stacked together.
- Applications and libc. A program calls the C library, which consults
/etc/nsswitch.confand then reads/etc/resolv.conf. - A stub resolver. On Ubuntu, Fedora and many others,
/etc/resolv.confpoints at127.0.0.53, which is the local listener of systemd-resolved. Other systems use dnsmasq or a different local cache. - The network manager. NetworkManager, systemd-networkd or ifupdown decides which DNS servers belong to which interface and tells the resolver.
- The browser. Firefox and Chromium-based browsers can ignore the system resolver and ask a DNS-over-HTTPS server directly.
- Containers and VMs. Docker, Podman and virtual machines often carry their own resolver settings.
A VPN client usually touches only one of those layers, and sometimes none. A tunnel created with a bare ip link add or a minimal WireGuard config with no DNS = line changes routes but leaves the resolver exactly as it was. That is the classic leak: web traffic goes into the tunnel while DNS questions still go to the router.

Step 1: find out who answers your DNS questions
Before you change anything, get a baseline with the VPN connected.
- Run
resolvectl status. For each interface (called a link) it lists the DNS servers, the search domains and a line namedDefault Route. If your physical link, such aswlp3s0, showsDefault Route: yesand the VPN link showsno, normal queries are going out the physical link. - Run
resolvectl query example.com. The last lines say which link answered, for examplelink: wlp3s0orlink: wg0. You want the VPN link. - Run
cat /etc/resolv.conf. If it containsnameserver 127.0.0.53, systemd-resolved is in charge. If it lists a private address such as192.168.1.1, the system is talking to the router directly. - Run
ip route get 1.1.1.1. The output names the interface the kernel would use for that destination. If it shows your physical interface, even your traffic is not in the tunnel yet, and you have a routing problem before a DNS problem.
If you do not use systemd-resolved, resolvectl will say the service is not running. Skip to the sections on NetworkManager and resolv.conf below.
Step 2: prove it on the wire
Configuration tells you what should happen. A packet capture tells you what does happen. Open two terminals.
In the first, run:
sudo tcpdump -ni any 'udp port 53 or tcp port 53'
In the second, request a few names you have not visited recently:
resolvectl flush-caches
getent hosts example.org
dig +short example.net
Read the interface column in the capture. Queries that appear on wg0 or tun0 are inside the tunnel and will show as encrypted traffic on the physical link. Queries that appear on wlp3s0 or eth0, addressed to your router or a public resolver, are leaving through the normal network. Those are the leaks.
Two details avoid false alarms. First, the stub address 127.0.0.53 always shows on the lo interface, and that is harmless because it is local. Second, DNS inside the tunnel is encrypted by the tunnel, so you will not see port 53 on the physical link at all when everything works; you will see only encrypted VPN packets. Finish with an online leak test from a browser to cross-check, and use the steps in how to test a VPN for the rest of your checks.
Reading the results
| What you see | What it means | Next move |
|---|---|---|
| Queries only on the VPN interface | No leak on this path | Test IPv6 and the browser next |
| Queries on the physical link to the router | Resolver still follows the old link | Set DNS per link and make the VPN link the default route |
| Queries to a public resolver on the physical link | Browser DoH or a hard-coded server | Check browser settings and application configs |
| Queries on both links alternately | Several default-route links | Remove DNS from the physical link or use routing domains |
| Nothing at all after the fix | Resolution may be broken | Check the VPN DNS address is reachable through the tunnel |
Fix 1: systemd-resolved with per-link DNS
This is the cleanest fix because systemd-resolved was designed for multiple interfaces. The idea is to give the VPN link its own DNS servers and mark it as the place for every domain.
- Set the servers on the VPN link:
sudo resolvectl dns wg0 10.0.0.1. Use the resolver address your VPN setup provides. - Make the link answer for every name by giving it the catch-all routing domain:
sudo resolvectl domain wg0 '~.'. The tilde means "route queries for this domain here without adding it to the search list". - Turn off the default route on the physical link so it only answers its own local names:
sudo resolvectl default-route wlp3s0 no. - Check again with
resolvectl statusandresolvectl query example.com.
These settings last only while the interface exists. To make them permanent in a WireGuard setup, put the DNS line in the config, for example DNS = 10.0.0.1, and wg-quick will hand it to the resolver tooling when the interface comes up. On systems where resolvconf is provided by systemd, that call ends up in the commands above. Verify with resolvectl status after every restart rather than assuming.
Fix 2: NetworkManager
When NetworkManager runs the connections, change DNS on the connection profile so that it survives reconnects.
- For the VPN profile, give it a negative priority:
nmcli connection modify "my-vpn" ipv4.dns-priority -50 ipv4.ignore-auto-dns yes. A negative value tells NetworkManager to use only the servers from that profile. - For the Wi-Fi or Ethernet profile, tell it not to use the router's DNS while the VPN is up:
nmcli connection modify "Home Wi-Fi" ipv4.ignore-auto-dns yes. Reconnect afterwards. - Add
ipv6.ignore-auto-dns yesas well if the network advertises an IPv6 resolver. - Reactivate with
nmcli connection downandupfor the changed profiles.
The trade-off is that after you disconnect from the VPN, the physical profile has no DNS of its own unless you set one. Many people keep two profiles for the same Wi-Fi network, or accept a brief manual change when they leave the VPN.
Fix 3: plain resolv.conf and other resolvers
On a minimal server or an older distribution, /etc/resolv.conf may be an ordinary file. You can write the VPN resolver into it, but anything that rewrites the file, such as a DHCP client, will undo your work. Two safer habits:
- Let the VPN script manage it. Tools such as
resolvconforopenresolvkeep a list of sources and merge them in priority order, so the VPN entry replaces the router entry while the tunnel is up and goes away afterwards. - If you must pin the file, make it a deliberate decision and document it. Using
chattr +ito freeze it also freezes every later legitimate change and often breaks the network on the next boot or move. Avoid it on laptops.
If you run a local caching resolver such as dnsmasq or unbound, change its upstream servers instead of the file, and restart it when the tunnel comes up and goes down.

IPv6 and browser DNS-over-HTTPS
Two leaks hide even from careful users. The first is IPv6. If the router advertises an IPv6 DNS server and your VPN only covers IPv4, queries can leave on the IPv6 path. Check resolvectl status for IPv6 addresses under the physical link. Either route IPv6 through the tunnel as well, or disable IPv6 on the connection with ipv6.method disabled in NetworkManager while you test. The article on IPv6 leaks goes deeper.
The second is the browser. Firefox can use DNS-over-HTTPS with its own provider list, and Chromium-based browsers can follow the system setting or their own. Those queries go inside an HTTPS connection to port 443, so they never appear in your port 53 capture and they ignore the resolver you fixed. Decide on purpose: either let the browser use the system resolver, or choose a DoH server knowingly. DNS over HTTPS versus a VPN explains how the two relate.
Block stray queries with a firewall rule
After the settings are right, add a safety net so that a future misconfiguration fails closed rather than leaking. A small nftables table drops plain DNS that tries to leave through any interface except the tunnel and loopback:
table inet dnsguard {
chain output {
type filter hook output priority 0; policy accept;
oifname != "wg0" oifname != "lo" udp dport 53 drop
oifname != "wg0" oifname != "lo" tcp dport 53 drop
}
}
Load it with sudo nft -f dnsguard.nft and remove it with sudo nft delete table inet dnsguard. Two warnings apply. First, while the rule is active and the tunnel is down, DNS will stop working entirely, which is the point but surprises people. Tie loading and removal to the interface coming up and going down, for example with PostUp and PostDown lines. Second, the VPN client must still resolve the server name, so use a literal IP address for the endpoint or load the rule only after the first connection. For a general view of this idea, see what a VPN kill switch is.
Common mistakes
- Testing only with a website leak test and never looking at a packet capture.
- Editing
/etc/resolv.confand wondering why it reverts after sleep. - Setting
DNS =in the VPN config but running on a system with noresolvconfor resolver integration, so the line is silently ignored. - Forgetting containers, which keep their own resolver and may bypass the host settings.
- Fixing IPv4 and leaving IPv6 advertised by the router.
- Assuming the leak is fixed because the public IP changed. The address and the resolver are two separate questions.
Summary
A Linux DNS leak is almost never the tunnel's fault. It is the resolver stack, the network manager, the browser or IPv6 keeping an old path. Find the answering layer with resolvectl, prove it with tcpdump, fix it with per-link DNS or connection priorities, and add a firewall rule so that mistakes fail closed. Repeat the test after every reboot and every network change.
If you connect with the free VPNclient app, the Linux setup guide covers installing it, and you can compare options on the pricing page when you are ready.
Frequently asked questions
Why can a Linux VPN leak DNS when the tunnel itself works?
The tunnel only carries packets that the routing table sends into it. DNS questions are produced by a separate resolver layer, and if that layer still points at the router's address, the questions travel through the normal network even though your web traffic goes through the VPN.
Which command shows where my DNS queries go?
On systems that use systemd-resolved, run resolvectl status to see the DNS servers per interface and resolvectl query example.com to see which link answered. For proof on the wire, run sudo tcpdump -ni any port 53 while you browse.
Is editing /etc/resolv.conf by hand a good fix?
Usually not. On most modern distributions the file is generated by systemd-resolved or NetworkManager and your edit is overwritten at the next network change. Set the DNS on the connection or the interface instead.
Do I need to worry about IPv6 for DNS leaks?
Yes. If your network hands out an IPv6 resolver and the VPN only covers IPv4, queries can leave through the IPv6 path. Check resolvectl status for IPv6 servers and either route IPv6 through the tunnel or disable it on that connection.
References
About the author

Bob Kanokphon Thongdee
- Founder of XPASS VPN
- Co-founder of eSIMonline.asia
- More than 7 years in online marketing
- Founder of Cojourney Visa and Cojourney Travel
Need a VPN for a short trip or a busy month?
XPASS sells prepaid passes for a set number of days. You pay once and nothing renews automatically.
See passesKeep reading

VPN Security
What Is a DNS Leak?
A DNS leak happens when your device asks for website addresses outside the VPN tunnel. Here is why it happens, how to test for it, and what to do about it.
10 min read

VPN Basics
How DNS Works: From Domain Name to IP Address
DNS is the lookup system that turns a website name into the IP address your device actually connects to. Here is how a lookup works, step by step, and why it matters for privacy.
9 min read

VPN Security
Split DNS with VPNs: What It Means
Split DNS lets a device ask one resolver about private names and another about everything else. Here is how it works, where it helps, and how to check it.
9 min read

Device Guides
How to Fix VPN DNS Leaks on Windows
Why Windows can send DNS lookups outside your VPN, how to confirm a leak with built-in tools, and the fixes in the order that works for most PCs.
10 min read

VPN Security
How to Test a VPN: Leaks, Speed and Kill Switch
A VPN is only useful if it does what it claims. This guide shows how to test any VPN yourself: leaks, kill switch, speed, latency, IPv6 and the app's own behaviour.
9 min read