WireGuard DNS Configuration for Systemd

The DNS setting of a standard WireGuard config file can be used to specify the DNS resolvers to query when the WireGuard interface is up, as well as the domains to search for unqualified hostnames. On Linux, the wg-quick program expects to be able to use the traditional resolvconf utility for this; however, most modern Linux distributions use systemd-resolved instead.

On distros that use systemd-resolved, you might see an error message like the following if you try to start up a WireGuard interface with wg-quick (or your WireGuard DNS settings might just be silently ignored, if the distro has an partial resolvconf stub installed instead):

resolvconf: command not found

Fortunately, it’s easy to configure wg-quick to apply your desired DNS settings to systemd-resolved directly, using a custom PostUp command. This article will show you how:

Check for systemd-resolved

To check if your system is using systemd-resolved, inspect the contents of the /etc/resolv.conf file. If the file starts with a line like the following, it’s using systemd-resolved:

$ cat /etc/resolv.conf
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
...

Override DNS for Specific Domains

If you use WireGuard to connect to an internal network, and that network includes a custom DNS resolver which resolves an internal domain name for hosts on that network, you can configure systemd-resolved to use that resolver for that particular domain name.

For example, if the resolver’s IP address is 10.0.0.2, and the domain name is internal.example.com, you might normally use the following DNS settting:

DNS = 10.0.0.2, internal.example.com

With systemd-resolved, however, instead of using the DNS setting, add the following PostUp command to the [Interface] section of your WireGuard config file:

PostUp = resolvectl dns %i 10.0.0.2; resolvectl domain %i ~internal.example.com

When you start your WireGuard interface up, this command will direct systemd-resolved to use the DNS server at 10.0.0.2 to resolve queries for the internal.example.com domain name (such as queries for mail.internal.example.com or chat.internal.example.com etc).

If you also want to use internal.example.com as a search domain (so that systemd-resolved will attempt to resolve queries for unqualified hostnames like mail or chat as if they were fully-qualified hostnames like mail.internal.example.com or chat.internal.example.com) remove the tilde (~) from the front of internal.example.com:

PostUp = resolvectl dns %i 10.0.0.2; resolvectl domain %i internal.example.com

If you have multiple custom domains (like example.com, example.net, and example.org) that you want your internal resolver to resolve, specify them together in the same command, separated by whitespace:

PostUp = resolvectl dns %i 10.0.0.2; resolvectl domain %i ~example.com ~example.net ~example.org

Override DNS Globally

If you use WireGuard to connect to the Internet — or just to a network with a recursive DNS resolver that you prefer to use over your default resolver — you can configure systemd-resolved to use that resolver globally.

For example, if you wanted to use the Quad9 resolver for all Internet DNS queries when your WireGuard interface is up, you’d normally use the following DNS setting:

DNS = 9.9.9.9, 149.112.112.112

With systemd-resolved, however, instead of using that DNS setting, add the following PostUp command to the [Interface] section of your WireGuard config file:

PostUp = resolvectl dns %i 9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net; resolvectl domain %i ~.

When you start your WireGuard interface up, this command will direct systemd-resolved to use the DNS server at 9.9.9.9 (or at 149.112.112.112, if 9.9.9.9 is not available) to resolve queries for any domain name.

Avoid DNS Settings From DHCP

If you also use Network Manager, and you connect to networks that you don’t trust, you may also want to adjust Network Manager’s settings for those networks to prevent them from changing your DNS settings (which they may do via DHCP, the Dynamic Host Configuration Protocol).

For example, to modify Network Manager’s settings for your saved Rando Coffee Shop connection to ignore any DNS settings it may push to you over DHCP, run this command:

nmcli connection modify 'Rando Coffee Shop' ipv4.ignore-auto-dns yes ipv6.ignore-auto-dns yes

Alternately, you can use the Network Manager UI for this: edit your Rando Coffee Shop connection, switch to its IPv4 Settings tab, and select the Automatic (DHCP) addresses only method:

Automatic (DHCP) addresses only

If you don’t allow DNS to be configured via DHCP, and you don’t configure any DNS servers through Network Manager, systemd-resolved will use the DNS resolvers configured in its base DNS setting from the /etc/systemd/resolved.conf file. There you can configure your preferred DNS servers; for example, to use Quad9:

# /etc/systemd/resolved.conf
DNS=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
DNSOverTLS=opportunistic

This base DNS setting will be overridden by any per-connection customizations you make with the PostUp commands above (or any per-connections settings you configure via Network Manager).