Back to Blog
Infrastructure23 July 2024Michael Hettwer5 min read

Server-side DNS resolution: systemd-resolved under control

How systemd-resolved structures name resolution on a server: per-interface upstreams, split DNS, encryption choices, and the debugging tools.

Name resolution is one of those services whose failure stops everything else, yet on many servers it is the least examined part of operations. systemd-resolved structures this area cleanly on Linux systems: a local resolver with a cache, separate upstream servers per network interface, and tools that let us inspect queries directly. This post shows the order the resolver brings and where we deliberately stay on simpler paths.

What the local resolver changes

The core is the stub: resolved occupies the address 127.0.0.53 and receives the system's queries there. Every application that works through the classic resolver interface ends up at one place, which in turn decides by the rules which upstream server answers the actual question. Three practical properties follow: a cache forms that spares frequent queries; the upstream servers are configurable per interface; and the diagnostic tools attach at one spot instead of being scattered across files.

That last property is the biggest win in daily work. resolvectl query answers a concrete question with the full path: which link was used, which server responded, how long it took. resolvectl statistics shows how the cache is filled, and resolvectl flush-cache ends the stale-entry discussion before it reaches a meeting.

Separate upstreams per connection

The model's strength shows with more than one network: a server with one uplink, one internal management network and a tunnel may have three different answers to the same question, depending on where the answer is supposed to come from. resolved accounts for that reality by keeping its own upstream servers per link and deciding through routing domains which query goes where. That is the mechanism that makes split DNS possible with modest means: the internal zone gets answered by the internal server, everything else by the public one.

For servers connected to remote networks through encrypted tunnels, this behavior is not a toy but the precondition for internal names working without everything riding the tunnel. Anyone who has run a tunnel where every query wandered into the distance and local lookups failed against a missing internal server knows the opposite of this order.

The setup of such a tunnel is covered in the post WireGuard site to site in practice.

The setup of such a tunnel is covered in the post WireGuard site to site in practice.

The setup of such a tunnel is covered in the post WireGuard site to site in practice.

Encryption and its limits

resolved can send queries to upstream servers encrypted, for example over DNS-over-TLS, and the documentation carefully distinguishes between "if the server supports it" and "encrypted only". The latter is the stricter setting, making the server let resolution fail where encryption is unavailable. Choosing that level is an operational decision and depends on which upstream servers exist. On servers with firmly defined internal upstreams the strict level is usually feasible; for general resolution into the internet it needs more careful weighing, because a failing resolver takes every affected service down with it.

DNSSEC validation is configurable too, but not free: a server that validates strictly fails on zones signed badly, and that concerns names nobody had on the radar. We turn validation on only where the consequences are known, and we document the decision.

Where we deliberately skip resolved

The order has a price: resolved is a moving part of the system with its own updates and its own failure modes. On servers whose job is to run DNS services themselves, on systems with very specific resolver requirements, and on boxes where every ingredient doubles the failure surface, we deliberately run a static resolv.conf and manage resolution as a file. That decision is no disparagement; it is the observation that here the simplest configuration is the most maintainable one.

What a clean resolver setup gives back in time

The time saved by an orderly resolver setup shows not in the configuration but in the failures. A resolution problem that is visible through the tools takes minutes instead of a session of guessing and renaming: the query gets repeated, the used link gets named, the responding server gets identified, and the question "cache or upstream" is decided with one look at the statistics. In environments where resolution problems previously cost half afternoons, that is the actual return of the topic.

The second gain is preventive: a resolver whose behavior is defined per interface prevents the quiet misconfigurations that only surface when a new service arrives. The classic case is the container host whose internal resolution runs a different path than the host itself, whose applications therefore find names the host cannot see. With separate upstreams per link, that trap becomes a documented decision: the container area gets its own upstream declarations, and the question gets asked at setup instead of being guessed during a failure.

A sentence about the effort belongs in the weighing: running the stub is not free in attention, because every change to the network interfaces touches the resolver's configuration. A server whose interfaces change rarely feels little of it; a system with dynamic connections, VPN dial-ins and containers bringing their own networks needs a disciplined hand. The question asked before adoption is therefore concrete: how often does this server's network landscape change? The answer sorts the cases better than any principled debate, and it prevents the adoption where it would later create maintenance effort without return.

For all other cases the direction inverts: the stub resolver with its tools makes resolution visible, and visible means failures get found before the applications start telling stories. If you want your servers' name resolution on such a footing, the network and firewall page describes the matching service, and the contact page is the fastest way to reach us.

Sources

  • systemd-resolved(8) manual page, https://man.archlinux.org/man/systemd-resolved.8.en (accessed 2026-11-03)
  • resolvectl(1) manual page, https://www.freedesktop.org/software/systemd/man/resolvectl.html (accessed 2026-11-03)
  • nss-myhostname(8) manual page, https://www.freedesktop.org/software/systemd/man/nss-myhostname.html (accessed 2026-11-03)