Disable systemd-resolved Cleanly

Over the last several years, systemd has steadily absorbed an increasing number of Linux functions that were previously simple config files and/or binaries. I honestly don’t have a strong opinion on systemd but it does make certain system admin-y tasks more complicated. One of the things that I reguarly run into is that systemd-resolved runs a “stub” DNS server that binds on 127.0.0.53:53 and takes over /etc/resolv.conf. Rather than being a text file, /etc/resolv.conf is instead, by default, a symlink to /run/systemd/resolve/stub-resolv.conf which uses the aforementioned stub DNS server as its nameserver.

For most use-cases, this works great and the stub DNS server provides some useful additional functionality. Unfortuantely, it also causes problems if you want to install a real DNS server as at least one interface already has a service bound on UDP port 53. This caused me problems when I spun up a pi-hole virtual machine (VM) as well as when I wanted to install a full-featured DNS server for my WireGuard VM. Searching around can lead you to several forums with people giving different advice.

The Common Solution

Outright disabling systemd-resolved has the nasty side effect of losing the ability to use DHCP to set your DNS server as that task is now delegated to systemd-resolved. Instead, many people point to editing /etc/systemd/resolved.conf, setting DNSStubListener to “no”, and then restarting systemd-resolved. Here’s what /etc/systemd/resolved.conf looks like afterwards:

[Resolve]
#DNS=
#FallbackDNS=
#Domains=
#LLMNR=no
#MulticastDNS=no
#DNSSEC=no
#DNSOverTLS=no
#Cache=no-negative
DNSStubListener=no
#ReadEtcHosts=yes

You then need to set /etc/resolv.conf to be a symlink to /run/systemd/resolve/resolv.conf. This version of the resolv.conf is a managed file that bypasses the stub DNS server but still respects the DNS server set by DNS (or netplan). You can create the symlink and restart systemd-resolved by doing:

sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved

I did this up until recently and then discovered that, since /etc/systemd/resolved.conf is installed by by a .deb, modifying it causes unattended-upgrade to fail out when systemd has an update because it wants a manual review of the clobbered config file.

The Clean Solution

I happened to be reading the man page for resolved.conf when I noticed that systemd-resolved supports “drop-in” config files. In general, drop-in config files have the benefit of still configuring the target program but not be controlled by a .deb file. This means that unattended-upgrade can still do its thing and not run into a situation where it wants a human to compare clobbered files. You first need to make the drop-in config file directory using:

sudo mkdir -p /etc/systemd/resolved.conf.d/

You then need to make a file at /etc/systemd/resolved.conf.d/disable-stub.conf (the name doesn’t matter but it must end in a “.conf”) with the following contents:

[Resolve]
DNSStubListener=no

As before, you still need to repoint /etc/resolv.conf to the non-stub file and restart systemd-resolved:

sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved

The stub DNS server should now be disabled and you’ll be prompted to do fewer manual reviews of config files in the future!

comments powered by Disqus