Why systemd‑resolved matters
On most modern distros the DNS stack is no longer a simple /etc/resolv.conf.systemd‑resolved runs in the background, pulls DNS servers from every
interface, does caching, validates with DNSSEC, and even acts as a local
DNS‑over‑TLS (DoT) proxy.resolvectl (now systemd-resolve in newer releases) is the CLI that lets you
look inside this stack and tweak it without hunting through config files.
If you run a home lab, self‑hosted services, or just want a snappier, more
reliable lookup, mastering resolvectl can shave milliseconds off each
query and give you a clear view of what the resolver is actually doing.
Getting the basics
# Show the current global resolver state
resolvectl status
The output lists:
- Global – default DNS servers used when no per‑link config exists.
- Links – each network interface and its assigned DNS servers.
- Cache – number of cached entries and hit rate.
- DNSSEC – whether validation is enabled.
If you see systemd-resolved in the list of services, the resolver is active.
Checking a single query
resolvectl query example.com
This performs a lookup using the current resolver configuration and prints the answer section. It also shows the source of the answer (cache, server, etc.).
Per‑link DNS configuration
systemd‑resolved automatically picks up DNS servers from DHCP, static
configurations, or NetworkManager. But you can override or add servers per
interface with resolvectl.
# Add a DNS server to the wired interface
sudo resolvectl dns eth0 2001:4860:4860::8888 8.8.8.8
# Set search domains for that link
sudo resolvectl domain eth0 example.com local
These settings are stored in /run/systemd/resolve/resolv.conf for the link
and are applied immediately. The advantage is that you can have:
- A public DNS (e.g., Google, Cloudflare) for general traffic.
- A private DNS (e.g., internal domain) for LAN services.
- Different DNSSEC settings per link.
Trade‑off: Over‑configuring can lead to confusion. Keep a single source of
truth—prefer systemd‑resolved over manual /etc/resolv.conf edits.
DNSSEC and privacy
systemd‑resolved supports DNSSEC validation out of the box. Enable it with:
sudo resolvectl dnssec 1
1 turns on validation; 0 disables it. Once enabled, every query will be
validated against the DNSSEC chain, protecting against cache poisoning.
If you need to trust a specific key or disable validation for a domain:
# Trust a key for a domain
sudo resolvectl trust-anchor example.com 8.8.8.8
# Disable validation for a domain
sudo resolvectl trust-anchor example.com 0
Security note: DNSSEC alone does not hide your queries. For privacy, combine DNSSEC with DNS‑over‑TLS.
DNS over TLS (DoT)
systemd‑resolved can act as a DoT client. First, enable the service:
sudo systemctl enable --now systemd-resolved
Then configure a DoT server:
sudo resolvectl dns eth0 1.1.1.1
sudo resolvectl options eth0 +tls
+tls tells systemd‑resolved to use TLS for queries to that server. The
resolver will automatically negotiate the TLS handshake and use the
dot port (853).
You can verify DoT usage with:
resolvectl status | grep -i dot
If you see TLS in the output, queries are encrypted.
Trade‑off: DoT adds a small latency (~10‑15 ms) due to TLS negotiation, but the privacy benefit outweighs it for most users. If you need the absolute fastest lookup, disable TLS for public servers that you trust.
Flushing and debugging
The cache can become stale if you change upstream servers. Flush it with:
sudo resolvectl flush-caches
To see the cache contents:
resolvectl dump
If a query fails, inspect the status:
resolvectl status
Look for:
Failedentries under Links.Cachehit/miss ratio.DNSSECvalidation failures.
Common troubleshooting steps:
- Check the link configuration – ensure the correct DNS servers are set.
- Verify connectivity – ping the DNS server on port 53 (or 853 for TLS).
- Look at system logs –
journalctl -u systemd-resolvedfor detailed errors.
Trade‑offs and alternatives
| Approach | Pros | Cons |
|---|---|---|
systemd‑resolved + resolvectl | Unified, fast cache, DNSSEC, DoT | Requires systemd; not available on minimal non‑systemd distros |
dnsmasq | Lightweight, easy to configure | No built‑in DNSSEC; separate service |
unbound | Full validation, flexible | More complex configuration |
/etc/resolv.conf only | Simple, works everywhere | No caching, no DNSSEC, no DoT |
If you run a minimal container or a system that does not use systemd,
dnsmasq or unbound are the next best options. For most desktop and server
setups, systemd‑resolved is the default and easiest path.
Security checklist
- Enable DNSSEC – protects against spoofed answers.
- Use DoT or DoH – hides query content from local eavesdroppers.
- Restrict per‑link DNS – avoid leaking internal domain names to public DNS.
- Keep
systemd-resolvedup to date – CVE‑2025‑xxxx fixed a DNS cache poisoning bug in 2025; ensure you run the latest kernel and systemd packages. - Audit the cache –
resolvectl dumpcan reveal unexpected entries that might indicate a compromised resolver.
Practical use cases
1. Dual‑stack home lab
You have a home network with an internal DNS (10.0.0.1) and a public DNS
(1.1.1.1). Configure both:
sudo resolvectl dns eth0 10.0.0.1 1.1.1.1
sudo resolvectl domain eth0 internal.local
Now, queries for *.internal.local go to the private server, while all other
queries go to Cloudflare. DNSSEC and DoT are enabled globally.
2. VPN‑only DNS
When connected to a VPN, you want all traffic to use the VPN’s DNS server
(10.8.0.1). Add a rule:
sudo resolvectl dns tun0 10.8.0.1
sudo resolvectl domain tun0 vpn.internal
The resolver automatically switches when the VPN interface comes up.
3. Performance tuning
If you notice high cache miss rates, increase the cache size:
sudo resolvectl cache-size 2048
Or disable the cache for a specific link:
sudo resolvectl cache-size eth0 0
Wrap‑up
You’re now equipped to read the resolver’s state, tweak per‑link settings,
enable DNSSEC, and push queries through DoT—all without touching a single
/etc/resolv.conf. Stick to systemd‑resolved for most desktop and server
environments, but remember the alternatives if you’re in a minimal or
non‑systemd world.
Happy hunting for those stubborn DNS hiccups!
TAGS: systemd-resolved, DNS
See also
- Why Your systemd Service Stays “activating” After a Kernel Upgrade – A Step‑by‑Step Fix
- Taming Duplicate Entries in Your Bash History with a Simple Script
- Taming systemd Restart Policies to Prevent Service Deluge
- Using rsync and SSH to Automate Offsite Backups of Important Configuration Files
- Recovering from a Failed Boot: Using systemd's Emergency Mode and Rescue Shell to Troubleshoot Initramfs Issues