Skip to content

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.conf and then reads /etc/resolv.conf.
  • A stub resolver. On Ubuntu, Fedora and many others, /etc/resolv.conf points at 127.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.

  1. Run resolvectl status. For each interface (called a link) it lists the DNS servers, the search domains and a line named Default Route. If your physical link, such as wlp3s0, shows Default Route: yes and the VPN link shows no, normal queries are going out the physical link.
  2. Run resolvectl query example.com. The last lines say which link answered, for example link: wlp3s0 or link: wg0. You want the VPN link.
  3. Run cat /etc/resolv.conf. If it contains nameserver 127.0.0.53, systemd-resolved is in charge. If it lists a private address such as 192.168.1.1, the system is talking to the router directly.
  4. 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

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.

  1. Set the servers on the VPN link: sudo resolvectl dns wg0 10.0.0.1. Use the resolver address your VPN setup provides.
  2. 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".
  3. Turn off the default route on the physical link so it only answers its own local names: sudo resolvectl default-route wlp3s0 no.
  4. Check again with resolvectl status and resolvectl 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 yes as well if the network advertises an IPv6 resolver.
  • Reactivate with nmcli connection down and up for 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 resolvconf or openresolv keep 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 +i to 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.conf and wondering why it reverts after sleep.
  • Setting DNS = in the VPN config but running on a system with no resolvconf or 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.

About the author

Bob Kanokphon Thongdee, founder of XPASS VPN

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 passes

Keep 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