Troubleshooting WireGuard DNS Issues
When your WireGuard tunnel is up, and you can access websites by IP address — but not by DNS name — you have a WireGuard DNS problem.
For example, if this first cURL command returns a response (even a 404 response):
$ curl -I https://9.9.9.9 HTTP/2 404 server: h2o/dnsdist date: Thu, 07 Sep 2023 21:33:27 GMT content-type: text/plain; charset=utf-8 content-length: 9
But this second command returns a DNS-resolution error:
$ curl -I https://quad9.net curl: (6) Could not resolve host: quad9.net
You have a WireGuard issue with DNS. This article will show you how to diagnose and fix it.
There are two flavors of this problem:
-
The first is when you’re trying to use a WireGuard-Specific DNS Resolver to which you can’t connect;
-
The second is when you can’t connect to your Default DNS Resolver while the WireGuard tunnel is up.
Tip
|
If DNS works when using cURL, but not when using a web browser, check your browser’s DNS settings — you may have customized your browser to override your system’s DNS settings. |
WireGuard-Specific DNS Resolver
If you’ve added a DNS
setting to your WireGuard config file, like the following, you’re trying to use a specific DNS resolver with your WireGuard interface:
# /etc/wireguard/wg0.conf
# local settings for Your Workstation
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.0.0.1/32
DNS = 10.10.0.2
# remote settings for WireGuard Server
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
Endpoint = 203.0.113.2:51820
AllowedIPs = 10.10.0.0/16
When this is the case, ask these five questions:
Do I even want a WireGuard-specific DNS resolver?
If you simply copied-and-pasted your WireGuard DNS
setting from somewhere else, ask yourself if you actually want to use a different DNS resolver than normal when your WireGuard tunnel is up.
If the answer is no, remove the DNS
setting from your WireGuard configuration — you don’t want it, and you don’t need it.
Tip
|
There are two reasons why you might want to use a WireGuard-specific DNS resolver:
|
Is the DNS resolver up?
The next question to ask is whether or not the DNS resolver you’ve set in your WireGuard configuration (like 10.10.0.2
in the above example) is up and listening for external connections on UDP port 53
.
If you have admin access to the DNS resolver, log into it, and check that it’s listening on UDP port 53
:
$ sudo ss -punl sport :53 State Recv-Q Send-Q Local Address:Port Peer Address:Port Process UNCONN 0 0 *:53 *:* users:(("coredns",pid=345,fd=8))
In the above example, the ss
command shows that the CoreDNS daemon is listening on UDP port 53
for all the server’s IP addresses (indicated by *:53
in the Local Address:Port
column).
However, in the below example, while the ss
command shows a DNS resolver running, this resolver is actually the systemd-resolved daemon listening on the server’s own loopback interface — which isn’t accessible to external connections:
$ sudo ss -punl sport :53 State Recv-Q Send-Q Local Address:Port Peer Address:Port Process UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=1570,fd=13))
If you don’t have admin access to the DNS resolver, try querying it from some other system that should have access to it. For example, if you’re trying to use 10.10.0.2
as your DNS resolver, try querying it from another system on the same 10.10.0.0/16
network:
$ nslookup quad9.net 10.10.0.2 ;; communications error to 10.10.0.2#53: host unreachable ;; communications error to 10.10.0.2#53: host unreachable ;; communications error to 10.10.0.2#53: host unreachable ;; no servers could be reached
The above example shows that the DNS resolver is not accessible from the system from which we’re trying to query it.
Tip
|
You can use several different command-line tools such as $ nslookup quad9.net 9.9.9.9 Server: 9.9.9.9 Address: 9.9.9.9#53 Non-authoritative answer: Name: quad9.net Address: 216.21.3.77 Name: quad9.net Address: 2620:0:871:9000::77 $ host quad9.net 9.9.9.9 Using domain server: Name: 9.9.9.9 Address: 9.9.9.9#53 Aliases: quad9.net has address 216.21.3.77 quad9.net has IPv6 address 2620:0:871:9000::77 quad9.net mail is handled by 10 mx4.quad9.net. quad9.net mail is handled by 20 mx2.quad9.net. quad9.net mail is handled by 5 mx1.quad9.net. $ dig quad9.net @9.9.9.9 ; <<>> DiG 9.18.12-0ubuntu0.22.04.2-Ubuntu <<>> quad9.net @9.9.9.9 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65528 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;quad9.net. IN A ;; ANSWER SECTION: quad9.net. 1200 IN A 216.21.3.77 ;; Query time: 20 msec ;; SERVER: 9.9.9.9#53(9.9.9.9) (UDP) ;; WHEN: Thu Sep 07 16:07:45 PDT 2023 ;; MSG SIZE rcvd: 54 |
Do I have a route to the DNS resolver?
The next question to ask is whether or not your system is able to route traffic to the WireGuard-specific DNS resolver through the correct network interface.
99% of the time, you want to route traffic to a WireGuard-specific DNS resolver trough the WireGuard interface itself.
In the following WireGuard configuration file, we’ve specified a DNS resolver of 172.17.0.2
, but the AllowedIPs
setting of the only WireGuard peer for this interface is restricted to 10.0.0.0/24
:
# /etc/wireguard/wg0.conf
# local settings for Your Workstation
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.0.0.1/32
DNS = 172.17.0.2
# remote settings for WireGuard Server
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
Endpoint = 203.0.113.2:51820
AllowedIPs = 10.0.0.0/24
This means that queries to the WireGuard-specific DNS resolver will not be routed through the WireGuard interface — which is almost always a problem.
The solution is either to correct the DNS
setting of our WireGuard config to use a DNS resolver that is actually within one the peers’ AllowedIPs
ranges; or to expand that range to include the DNS resolver. In this case, we’ll add the DNS resolver to the AllowedIPs
ranges:
# /etc/wireguard/wg0.conf
# local settings for Your Workstation
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.0.0.1/32
DNS = 172.17.0.2
# remote settings for WireGuard Server
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
Endpoint = 203.0.113.2:51820
AllowedIPs = 10.0.0.0/24, 172.17.0.2/32
We can verify that our system will now correctly route the DNS resolver 172.17.0.2
out its wg0
interface by running the following command iproute2 command:
$ ip route get 172.17.0.2 172.17.0.2 dev wg0 src 10.0.0.1 uid 1000 cache
Is a firewall blocking connections to the DNS resolver?
The next question to ask is whether a firewall between your system and the DNS resolver is blocking queries to it.
If you know the DNS resolver is up and available, and that you have a route to it when your WireGuard interface is up, you should be able to query the DNS resolver from your local system using a tool like nslookup
, host
, or dig
(as mentioned above).
If you instead get an error when you try to query the DNS resolver, there is likely a firewall between you and the DNS resolver blocking your UDP port 53 connections to it:
$ nslookup quad9.net 10.10.0.2 ;; communications error to 10.10.0.2#53: host unreachable ;; communications error to 10.10.0.2#53: host unreachable ;; communications error to 10.10.0.2#53: host unreachable ;; no servers could be reached
You can try to further pinpoint the problem by running tcpdump as shown in the Troubleshooting WireGuard with Tcpdump article. To use the technique shown by the article, make the following two adjustments to the commands shown in the article:
-
Substitute the DNS resolver address (eg
10.10.0.2
) for the address used by thetcpdump
commands (ie192.168.200.22
). -
Substitute the test DNS query (eg
nslooklup quad9.net 10.10.0.2
) for the whole cURL command (iecurl 192.168.200.22
).
Tip
|
Make sure you also use the correct WireGuard listen ports in the
You should run this
And this
|
Am I using systemd?
The last question to ask is whether you’re using systemd on the client system.
If you are, you’re probably using the systemd-resolved stub resolver to resolve DNS queries on your system. In that case, try replacing the DNS
setting in your WireGuard config with a PostUp
command that runs systemd’s resolvectl
utility to alter your DNS settings when the WireGuard interface starts up:
#DNS = 10.10.0.2
PostUp = resolvectl dns %i 10.10.0.2
See the WireGuard DNS Configuration for Systemd article for more information.
Default DNS Resolver
If you haven’t added an explicit DNS
setting (or resolvectl
command) to your WireGuard config file, you’re using the same default DNS resolver when your WireGuard tunnel is up as when it is down.
In that case, if DNS is not working when your WireGuard tunnel is up, it means that connections to your default DNS resolver are being routed through the WireGuard tunnel when the tunnel is up — but your default DNS resolver is not accessible through the WireGuard tunnel. There are two ways to fix this:
Add a WireGuard-specific DNS resolver
Most of the time when you can’t access your default DNS resolver when your WireGuard tunnel is up, you’ll want to configure a specific DNS resolver to use for the WireGuard tunnel. To do so, add a DNS
setting to your WireGuard config:
# /etc/wireguard/wg0.conf
# local settings for Your Workstation
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.0.0.1/32
DNS = 9.9.9.9, 149.112.112.112, 2620:fe::fe, 2620:fe::9
# remote settings for WireGuard Server
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
Endpoint = 203.0.113.2:51820
AllowedIPs = 0.0.0.0/0, ::/0
If you’re using systemd, instead add a PostUp
command that runs the resolvectl
utility to achieve a similar result:
# /etc/wireguard/wg0.conf
# local settings for Your Workstation
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.0.0.1/32
PostUp = resolvectl dns %i 9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net; resolvectl domain %i ~.
# remote settings for WireGuard Server
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
Endpoint = 203.0.113.2:51820
AllowedIPs = 0.0.0.0/0, ::/0
Add a route for your default DNS resolver
Alternatively, if you want to continue to use your default DNS resolver when your WireGuard interface is up (and it is not already working out-of-the-box), you’ll need to add an explicit route for the resolver. To add a route for it, you need to know what the resolver’s IP address is, and what route is normally used to access it when your WireGuard interface is not up.
On Linux, traditionally you could find the IP address of your default DNS resolver simply by inspecting the nameserver
field of your /etc/resolv.conf
file:
$ grep nameserver /etc/resolv.conf nameserver 127.0.0.53
However, if your system is running its own stub DNS resolver (as is the case with the example above), the nameserver will simply be the local host (ie part of the 127.0.0.0/8
network) — and you’ll have to check the stub resolver in order to figure out what resolver the stub itself is using.
If your system is using the systemd-resolved stub resolver, use the resolvectl
utility figure out what default DNS resolver it’s actually using:
$ resolvectl status Global Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported resolv.conf mode: stub Link 2 (eth0) Current Scopes: DNS Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported Current DNS Server: 10.10.0.2 DNS Servers: 10.10.0.2 DNS Domain: corp
Then, when the WireGuard interface is down, use the ip route get
command to determine the correct route to the resolver:
$ ip route get 10.10.0.2 10.10.0.2 via 192.168.1.1 dev eth0 src 192.168.1.23 uid 1000 cache
Finally, add the route (using a PreUp
command — and delete it with a corresponding PostDown
command) in your WireGuard config:
# /etc/wireguard/wg0.conf
# local settings for Your Workstation
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.0.0.1/32
PreUp = ip route add 10.10.0.2 via 192.168.1.1 dev eth0
PostDown = ip route del 10.10.0.2 via 192.168.1.1 dev eth0
# remote settings for WireGuard Server
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
Endpoint = 203.0.113.2:51820
AllowedIPs = 0.0.0.0/0, ::/0