"How Do I configure a local caching DNS stub Resolver using "systemd-resolved"?"

I've been using BIND to enhance performance by caching name queries on hosts. Since systemd-resolved is part of the systemd furniture, I decided to adopt it in lieu of using BIND.

However, what should have been trivial to configure turned into an exercise in confusion: not much on systemd-resolved on the 'net and what I found varied materially by both systemd version and OS. There's man systemd-resolved, but this alone won't get you across the finish line.

I document in the answer below how I arrived at a correctly working IPv4/IPv6 systemd-resolved DNS caching stub resolver on Raspbian so hopefully others will avoid wasted time, effort & grief.


Firstly, identify the version of systemd on your system. This is crucial to understanding the validity of systemd-resolved links you're reading on the 'net:

systemctl --version

In respect to systemd-resolved, systemd v239 has some material changes. If you see "resolvectl" being mentioned, the document you're reading relates to systemd-resolved as ships with systemd v239 or later. At the time of this writing Raspbian is using v232

No need to install systemd-resolved on Raspbian- it's already there. HOWEVER: you MUST install libnss-resolve. It although systemd-resolved is installed, this dependency is NOT:

apt-get install libnss-resolve

Let's find the files we have to work with:

locate resolved

Note: locate command requires mlocate to be installed.

systemd-resolved 's own resolv.conf can't be read directly but must be exposed as a symlink to /etc/resolv.conf

rm -f /etc/resolv.conf
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

/run/systemd/resolve/resolv.conf is populated with the DNS resolvers specified in /etc/systemd/resolved.conf. Mine looks as follows:

/etc/systemd/resolved.conf :

DNS= 2001:4860:4860::8888
FallbackDNS= 2001:4860:4860::8844

You'll note the first resolver is an RFC1918 non-world-routable IP: why use this?!?! Because that's my Pi's router GW connection which has been set to cache DNS queries. So the Pi will try to resolve from the router's cache first and if the query cannot be answered there, systemd-resolveed will reach out across the 'net to a distant DNS server.

So as soon as any host in the subnet resolves a name now, all the Pi's can grab that mapping from the router and it will be cached locally making everything a bit snappier.

Even if the router is rebooted and its' DNS cache is consequently blown-away, the Pi's will retain their DNS caches. Sweet.

Add "resolve" to the front of the list so name resolution is attempted by the stub resolver first:

hosts:          resolve dns files mdns4_minimal [NOTFOUND=return]

/etc/dhcpcd.conf: In order to bypass DHCP assigning our DNS servers, we need to tweak this file by removing domain_name_servers to look as below:

#option domain_name_servers, domain_name, domain_search, host_name
option domain_name, domain_search, host_name

Finally, we need to read the changes we just made to /etc/systemd/resolved.conf:

systemctl daemon-reload
systemctl restart systemd-resolved

If you look at /etc/resolv.conf now, you'll see the DNS servers you specified.

If your config is righteous, should see a status as below:

sudo systemctl status systemd-resolved
● systemd-resolved.service - Network Name Resolution
   Loaded: loaded (/lib/systemd/system/systemd-resolved.service; disabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/systemd-resolved.service.d
   Active: active (running) since Wed 2019-04-24 16:27:10 BST; 9min ago
     Docs: man:systemd-resolved.service(8)
  Process: 17635 ExecStartPost=/bin/sh -c [ ! -e /run/resolvconf/enable-updates ] || echo "nameserver" | /sbin/resolvconf -a systemd-resolved (code=exited, status=0/SUCCESS)
 Main PID: 17634 (systemd-resolve)
   Status: "Processing requests..."
   CGroup: /system.slice/systemd-resolved.service
           └─17634 /lib/systemd/systemd-resolved

Lets run some tests:

ping -c1 www.google.com
ping6 -c1 www.google.com

Yes, those ping by name.

Let's resolve directly against the systemd-resolved local caching stub resolver next:

systemd-resolve www.microsoft.com
systemd-resolve www.microsoft.co.uk

NOTE: systemd-resolve is pre- systemd v239. Use resolvectl query instead if systemd version is v239 or later

Results will look as follows:

pi@pi3Bplus-tablet:~ $ systemd-resolve www.microsoft.com
www.microsoft.com: 2a02:26f0:ec:39d::356e
-- Information acquired via protocol DNS in 55.6ms.
-- Data is authenticated: no pi3Bplus-tablet

-- Information acquired via protocol DNS in 3.9ms.
-- Data is authenticated: yes

Now let's look at our cache statistics:

pi@pi3Bplus-tablet:~ $ systemd-resolve --statistics
DNSSEC supported by current servers: no
Current Transactions: 0
  Total Transactions: 14
  Current Cache Size: 6
          Cache Hits: 7
        Cache Misses: 7
DNSSEC Verdicts
              Secure: 0
            Insecure: 0
               Bogus: 0
       Indeterminate: 0

Another useful command is:

systemd-resolve --status

NOTE: Any time you either reboot or systemctl restart systemd-resolved you'll blow-away the cache which lives in memory. Obviously cold caches are non-performant, so avoid doing this if possible.

Can't over-emphasize the importance of employing caching of DNS queries on a local stub resolver. This will have a material impact on performance.

I think I've covered it all. If you spot any errors or omissions please ping me and I'll make the appropriate updates. HTH folks- T

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.