DNS resolution sits on the critical path of almost every network operation โ every HTTP request, package install, mail delivery, and database connection starts with a name lookup. A poorly tuned /etc/resolv.conf adds 100โ500 ms to every connection, magnifies tail latency under load, and turns a transient DNS hiccup into a service-wide outage. This guide walks through the resolver options that matter on production Linux servers and how to verify them.
How the stub resolver actually works
On modern distributions (Ubuntu 18.04+, RHEL 8+, Debian 11+), /etc/resolv.conf is usually a symlink managed by systemd-resolved, NetworkManager, or resolvconf. Always check what is actually consuming it before editing:
ls -l /etc/resolv.conf
resolvectl status # systemd-resolved view
nmcli dev show | grep -i dns # NetworkManager view
If the file is a symlink to /run/systemd/resolve/stub-resolv.conf, manual edits are overwritten on the next network event. Edit the upstream source instead (e.g. /etc/systemd/resolved.conf) or use resolvectl dns <iface> 1.1.1.1 9.9.9.9.
The options line that fixes 90% of pain
Add an options line at the bottom of /etc/resolv.conf (or via ResolvedExtra in resolved.conf):
nameserver 1.1.1.1
nameserver 9.9.9.9
options timeout:2 attempts:2 rotate single-request-reopen
- timeout:2 โ wait 2 s instead of the default 5 s before failing over to the next nameserver.
- attempts:2 โ try each nameserver twice before giving up; default of 2 is fine, but make it explicit.
- rotate โ round-robin across nameservers instead of always hitting the first one. Spreads load and surfaces a flaky resolver quickly.
- single-request-reopen โ opens a new socket for each A/AAAA query. Critical on systems behind stateful firewalls that drop the parallel A+AAAA pair from glibc.
IPv6 vs IPv4 ordering
If your server is IPv4-only but receives slow or hung lookups, glibc may be issuing AAAA queries that are silently dropped. Disable AAAA by adding options no-aaaa (glibc 2.32+) or by configuring /etc/gai.conf to prefer IPv4:
precedence ::ffff:0:0/96 100
For dual-stack hosts, leave AAAA enabled but make sure egress IPv6 actually works โ half-broken IPv6 is the single biggest source of "DNS is slow" tickets.
Caching: a 5 ms win you cannot skip
Without a local cache every fresh process re-resolves names from scratch. Enable a local resolver cache:
sudo systemctl enable --now systemd-resolved
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
resolvectl statistics # cache hits/misses
Alternatives: dnsmasq (simple, scriptable) or unbound (recursive, DNSSEC-validating). On Kubernetes nodes, NodeLocal DNSCache delivers the same benefit for pod traffic.
DNS over TLS for sensitive workloads
Plaintext DNS leaks every host your server connects to. With systemd-resolved:
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com 9.9.9.9#dns.quad9.net
DNSOverTLS=yes
DNSSEC=allow-downgrade
Cache=yes
Restart with systemctl restart systemd-resolved and confirm with resolvectl status โ the upstream should show +DNSOverTLS.
Validation checklist
- Resolve a known-good name and time it:
time dig +short example.com @127.0.0.53(under 50 ms is healthy). - Force a failover: temporarily firewall the first nameserver and confirm queries succeed within ~2 s.
- Watch real traffic:
sudo tcpdump -ni any port 53during a deploy; you should not see thousands of duplicate queries. - Monitor: alert on
resolvectl statisticsfailure ratio > 1% over 5 min.
Common mistakes to avoid
- Editing
/etc/resolv.confdirectly when it is a managed symlink โ the change disappears on the next DHCP renewal. - Listing the same nameserver twice "for redundancy" โ that is one server, not two.
- Leaving the default 5 s timeout in production โ a single packet loss now costs you a 5 s stall.
- Forgetting to set
searchdomains, then wondering whydbdoes not resolve todb.internal.example.com.
A correct resolver configuration is invisible when it works and catastrophic when it fails. Spend ten minutes hardening resolv.conf on every server you own โ the latency and reliability dividends compound across every other service you run.