Andrew Mercer
on this page

1. What systemd-resolved Is

systemd-resolved is the local DNS resolution service built into systemd, running as systemd-resolved.service on most modern Linux distributions (Ubuntu since 16.10 by default, Fedora, Arch optionally). It occupies a different niche than everything else in this set of guides: it is not meant to be a network-wide resolver for other machines — it's a per-host stub resolver and cache, sitting between applications on that single machine and whatever upstream DNS servers (from DHCP, static config, or VPN-pushed settings) are actually configured.

Its most visible effect, and the most common source of confusion, is that on a systemd-resolved-managed system, /etc/resolv.conf typically no longer points at real upstream DNS servers at all — it points at 127.0.0.53, systemd-resolved's own local stub listener.

2. Architecture

Application (getaddrinfo)
        │
   /etc/resolv.conf → nameserver 127.0.0.53
        │
systemd-resolved (stub listener :53 on 127.0.0.53)
        │
   ┌────┴─────────────────┐
   │                       │
per-link DNS config   global fallback DNS
(from DHCP, NM, VPN)  (resolved.conf)
        │
   real upstream resolvers

systemd-resolved maintains per-link (per-network-interface) DNS configuration — each interface (Ethernet, Wi-Fi, a VPN tunnel) can have its own upstream servers and search domains, learned from DHCP or pushed by a VPN client, and resolved picks which link's servers to query based on routing-domain matching for a given name. This is what correctly makes a VPN-provided internal domain resolve only through the VPN's DNS server while everything else still resolves through the regular network connection — a scenario that's historically been a persistent pain point with simpler single-resolv.conf setups.

3. Key Commands

# Overall status: per-link servers, domains, DNSSEC/DoT state
resolvectl status

# Query a name (uses resolved, exercising the same path apps use)
resolvectl query example.com

# Show/flush the cache
resolvectl statistics
sudo resolvectl flush-caches

# Set DNS servers for a specific link manually (overrides DHCP for that link)
sudo resolvectl dns eth0 1.1.1.1 1.0.0.1

# Set search domains for a link
sudo resolvectl domain eth0 example.local

(systemd-resolve was the older command name pre-systemd 239; resolvectl is current — both may appear in older documentation/scripts.)

4. Configuration File

/etc/systemd/resolved.conf

[Resolve]
DNS=1.1.1.1 1.0.0.1
FallbackDNS=8.8.8.8 8.8.4.4
Domains=~.
DNSSEC=allow-downgrade
DNSOverTLS=opportunistic
Cache=yes
  • DNS= — global default servers, used for links that don't get their own from DHCP/NM.
  • FallbackDNS= — used only if no other servers (global or per-link) are configured at all.
  • Domains= — routing domains; ~. means "use these servers for all names not matched by a more specific domain," the global-fallback routing equivalent.
  • DNSSEC= — yes (strict, fails closed), no, or allow-downgrade (validate when possible, don't hard-fail when upstream doesn't support it — the practical default on most distros, since strict mode breaks against many real-world networks whose captive portals/ISP resolvers don't cleanly support DNSSEC).
  • DNSOverTLS= — yes (required), no, or opportunistic (try DoT, silently fall back to plaintext if the upstream doesn't support it — trades the strong DoT authentication guarantee for compatibility, functionally similar to Unbound's DoT config without the #hostname verification suffix).

5. Interaction with NetworkManager and DHCP

On most desktop distributions, NetworkManager (or systemd-networkd) pushes DNS servers learned from DHCP into systemd-resolved automatically via its D-Bus API, per-link — this is why manually editing /etc/resolv.conf on these systems is ineffective and gets silently overwritten: it's a generated symlink (/etc/resolv.conf -> /run/systemd/resolve/stub-resolv.conf or similar), not the actual source of truth. The correct places to override DNS on such a system are resolvectl (runtime), NetworkManager's own per-connection DNS override, or /etc/systemd/resolved.conf (persistent global default) — editing /etc/resolv.conf directly is the wrong layer.

6. The /etc/resolv.conf Confusion

This is the single most common practical issue people run into:

Symlink target Meaning
/run/systemd/resolve/stub-resolv.conf Points at 127.0.0.53 — the stub; this is the modern, recommended setup
/run/systemd/resolve/resolv.conf Points at the actual upstream servers directly, bypassing the stub — used when something needs to see real servers (some VPN/container setups)
Neither (static file) systemd-resolved isn't managing resolution at all, or was disabled/masked

resolvectl status and readlink -f /etc/resolv.conf together are the fastest way to determine which mode a given machine is actually in — assuming stub-mode behavior on a machine that isn't in it (or vice versa) leads to a lot of wasted troubleshooting time. Some container runtimes and VPN clients specifically require the non-stub variant because they can't reach 127.0.0.53 from inside a network namespace, which is why distros often ship both symlink targets as an option.

7. Caching Behavior

systemd-resolved caches answers locally per the standard TTL rules, visible via resolvectl statistics (cache hits/misses, transaction counts). This cache is separate from and in addition to whatever caching the actual upstream resolver (a router's dnsmasq, an ISP resolver, Unbound) also performs — a change made upstream can still take a moment to be visible on the local machine even after the upstream's own cache/TTL has expired, purely due to this local layer; resolvectl flush-caches clears it directly when testing.

8. Multicast DNS and LLMNR

systemd-resolved also handles mDNS (multicast DNS, .local name resolution via Avahi/Bonjour-style discovery) and LLMNR (Link-Local Multicast Name Resolution, a Windows-originated fallback protocol) for the local network segment, independent of the unicast DNS path described above. These are enabled/disabled per-link with MulticastDNS= and LLMNR= in resolved.conf or per-connection in NetworkManager — worth knowing about specifically because a name like mydevice.local resolving on a LAN despite no DNS server anywhere configuring it is almost always mDNS, not DNS proper, and troubleshooting it with dig/resolvectl query behaves differently than a normal unicast lookup.

9. When It's the Wrong Tool

systemd-resolved is a single-host resolver/cache — it isn't meant to, and doesn't cleanly, serve DNS to other machines on a network the way dnsmasq, Pi-hole, Unbound, or BIND do. If the goal is "one box on my LAN that resolves for every other device," reach for one of those instead; systemd-resolved is what's already running locally on each individual Linux machine regardless.

  • systemd-resolved man page: https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html
  • resolved.conf man page: https://www.freedesktop.org/software/systemd/man/resolved.conf.html
  • resolvectl man page: https://www.freedesktop.org/software/systemd/man/resolvectl.html