systemd-resolved’s stub resolver configuration is less about setting DNS servers directly and more about how it chooses to query them, a subtlety that trips up many when troubleshooting DNS resolution.
Let’s see systemd-resolved in action. Imagine a typical setup where your router is your upstream DNS server, and systemd-resolved is configured to use it.
# Check current DNS servers systemd-resolved is using
resolvectl status
# Output might look like this:
# Global
# Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=allow-downgrade
# resolv.conf mode: stub
#
# Link 2 (eth0)
# Current Scopes: DNS
# Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=allow-downgrade
# DNS Servers: 192.168.1.1
# DNS Domain: example.com
#
# Link 3 (wlan0)
# Current Scopes: mDNS
# Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=allow-downgrade
# DNS Servers: 192.168.1.1
# DNS Domain: example.com
Here, resolv.conf mode: stub is key. This means /etc/resolv.conf (if it exists and is managed by systemd-resolved) will point to 127.0.0.53, systemd-resolved’s local stub listener. When an application queries 127.0.0.53, systemd-resolved intercepts it and decides which upstream DNS server (like 192.168.1.1 in this example) to use for the actual query.
The problem systemd-resolved solves is efficiently managing DNS resolution across multiple network interfaces, supporting modern DNS features like DNS-over-TLS (DoT) and DNSSEC, and providing a consistent interface for applications regardless of the underlying network configuration. It acts as a local caching DNS stub resolver.
Internally, when an application makes a DNS query to 127.0.0.53:
systemd-resolvedreceives the query.- It checks its cache. If the answer is there and valid, it returns it immediately.
- If not cached, it consults its configuration for the relevant network interface (or global settings if no interface-specific config is found).
- Based on the interface’s configured DNS servers, DNSSEC settings, and whether DNS-over-TLS is enabled, it constructs an appropriate query to an upstream DNS server.
- It sends the query, waits for the response, caches it, and returns it to the application.
The exact levers you control are primarily within /etc/systemd/resolved.conf and per-interface configurations (e.g., via netplan or NetworkManager .link files).
Global Configuration (/etc/systemd/resolved.conf):
DNS=: A space-separated list of DNS servers to use globally if no interface-specific servers are found.FallbackDNS=: A list of DNS servers to use if the primary servers fail.Domains=: A space-separated list of domains for which to search.DNSSEC=: Controls DNSSEC validation (allow-downgrade,yes,no).DNSOverTLS=: Controls DNS-over-TLS (no,opportunistic,yes).
Per-Interface Configuration:
This is where things get interesting. systemd-resolved prioritizes interface-specific settings. For example, if NetworkManager or netplan configures DNS servers for eth0, systemd-resolved will use those for queries originating from eth0. The resolvectl command is your primary tool for inspecting and sometimes overriding these.
The resolv.conf mode setting in resolvectl status is critical. When set to stub, /etc/resolv.conf will typically contain nameserver 127.0.0.53. This is the default and recommended mode. If it’s set to upload, /etc/resolv.conf will contain the actual upstream DNS servers. If it’s foreign, systemd-resolved is not managing /etc/resolv.conf at all. The stub mode allows systemd-resolved to act as a central point for DNS resolution, managing its own upstream queries and caching, which is more efficient and flexible.
Most people don’t realize that when you set DNS= in /etc/systemd/resolved.conf or via netplan, you’re not directly telling applications to use those servers. You’re telling systemd-resolved to use them. Applications, in stub mode, are always directed to 127.0.0.53. systemd-resolved then translates your configuration into actual upstream queries. This indirection is powerful for features like DoT, where systemd-resolved can establish a DoT connection to an upstream server even if the application itself doesn’t support it.
The next hurdle is understanding how DHCP-provided DNS servers interact with static configurations and how resolvectl domain <interface> ~. can be used to clear DNS search domains for a specific interface.