Runbook: DNS failure - restore name resolution
1 · Prerequisites
Confirm every item is in place before any state change.
2 · Pre-checks
Read-only diagnostic commands. If any of these don't match expected output, stop and investigate further.
- · Confirm the symptom: reproduce the failure from a known-good source
- · Identify whether one host or many are affected
- · Capture the current resolver configuration before changing anything
3 · Procedure
Execute each step in order. Verify the expected output of a step before moving to the next.
- 1Test the local resolver (127.0.0.53 or /etc/resolv.conf)
- 2Test the configured upstream resolver with dig @<ip>
- 3Test an external resolver (8.8.8.8) to isolate local vs upstream
- 4If small answers work and large ones do not, isolate the transport: dig TXT +notcp +bufsize=512, then +notcp +bufsize=4096, then +tcp
- 5Use dig +trace to walk the resolution chain
- 6Check resolvectl statistics and flush the cache if stale
- 7Bypass DNS with /etc/hosts as a temporary workaround
- 8Apply the fix (restart resolver, change resolver, etc.)
- 9Verify with dig, getent, and curl
4 · Verification
Confirm the procedure actually fixed the problem.
- ✓dig example.com returns the expected IP
- ✓getent hosts example.com returns the same answer
- ✓curl -I https://example.com succeeds
- ✓resolvectl status shows the service active and synchronised
5 · Rollback
If verification fails, undo the procedure in reverse order.
- ↶Restore /etc/resolv.conf from backup or the previous known-good version
- ↶Restart systemd-resolved and network manager
- ↶Remove any temporary /etc/hosts entries once DNS is restored
- ↶Revert any temporary firewall rules added for DNS debugging
6 · Escalation
When the runbook isn't enough, contact:
- · If the failing resolver is shared infrastructure, escalate to the DNS team immediately
- · If DNSSEC validation is failing for many names, escalate to the security team - this may indicate a chain compromise
- · If the issue is upstream (public DNS outage), monitor status pages and communicate to stakeholders
- · If the fix involves changing authoritative DNS for a production zone, escalate before changing
This runbook triages a DNS failure: hosts cannot resolve names, services that depend on DNS fail. The goal is to identify the failing layer (local resolver, upstream resolver, or authoritative server) and restore resolution within 30 minutes.
When to use this runbook
Use this runbook when:
- A host or service reports “DNS not working”.
- A user reports they cannot reach a service by name.
- An integration test fails because of a hostname resolution failure.
- DNS monitoring alerts.
Inputs
Gather before starting:
- Symptom: exact error (NXDOMAIN, SERVFAIL, timeout, connection refused).
- Affected hosts: how many, which ones.
- Affected services: which services depend on DNS.
- Time started: when did it start?
- Recent changes: DNS changes, network changes, host changes.
Procedure
Step 1: Confirm the symptom
Reproduce the failure from a known-good source:
dig example.com
nslookup example.com
getent hosts example.com
curl -I https://example.comNote the exact error. NXDOMAIN, SERVFAIL, timeout, and connection refused are different failures with different causes.
Step 2: Capture the configuration
ls -l /etc/resolv.conf
cat /etc/resolv.conf
resolvectl status 2>/dev/null
grep hosts /etc/nsswitch.confDocument the resolver configuration. If the file is a symlink to systemd-resolved, the resolver is systemd-resolved.
Step 3: Test the local resolver
dig @127.0.0.1 example.com # if running a local resolver
dig @127.0.0.53 example.com # systemd-resolvedIf this fails, the local resolver is the problem. Try flushing the cache before restarting anything — it is non-disruptive and resolves the most common case, a cached negative answer:
resolvectl flush-caches # systemd-resolved
sudo sss_cache -E # sssd: expire all cached entriesIf a flush does not fix it, restart only the caching layers this
host actually runs. Do not restart a daemon blindly: on a host
without it the command fails and adds noise to the incident,
and nscd in particular is deprecated in modern glibc and is
not installed by default on current RHEL, Fedora, Debian or
Ubuntu — its role is filled by systemd-resolved or sssd.
for u in systemd-resolved sssd nscd unbound dnsmasq; do
systemctl list-unit-files "$u.service" --no-legend | grep -q . || continue
systemctl is-active --quiet "$u" || continue
echo "restarting $u"; sudo systemctl restart "$u"
doneStep 4: Test the configured upstream
dig @<configured-resolver-ip> example.comIf this fails, the upstream resolver is the problem. Try the fallback:
dig @8.8.8.8 example.com
dig @1.1.1.1 example.comIf both upstream and fallback fail, the problem is upstream of your resolvers (your network or the global DNS).
If small answers resolve but large ones do not, hold the resolver and the name constant and vary only the transport:
dig @<configured-resolver-ip> example.com TXT +notcp +bufsize=512
dig @<configured-resolver-ip> example.com TXT +notcp +bufsize=4096
dig @<configured-resolver-ip> example.com TXT +tcp+notcp forbids the automatic fallback to TCP, so a truncated
answer stays truncated instead of being papered over. +tcp
sends the query over TCP/53 directly.
| UDP 512 | UDP 4096 | TCP | Conclusion |
|---|---|---|---|
| works | works | works | Transport is healthy. Look elsewhere. |
| works (TC set) | fails | works | Large or fragmented UDP is dropped in the path. |
| works | works | fails | TCP/53 is blocked by a firewall. |
| fails | fails | works | UDP/53 is blocked entirely. |
Step 5: Test the authoritative server
dig +trace example.comIf +trace fails at the authoritative server, the zone is
broken. Wait for recovery or escalate to the zone owner.
Step 6: Check the cache
resolvectl statisticsHigh cache hit rate is good. Low hit rate may indicate a cache eviction problem.
If you suspect stale cache:
resolvectl flush-cachesRetry the failing query.
Step 7: Bypass DNS
If you need immediate service restoration while fixing DNS,
bypass DNS by editing /etc/hosts:
echo "10.0.0.5 db.example.com" | sudo tee -a /etc/hostsThe files NSS module reads /etc/hosts before DNS. This
is a temporary fix; remove the entry once DNS is restored.
Step 8: Common fixes
Wrong resolver IP:
sudo nmcli connection modify "Wired connection 1" \
ipv4.dns "10.0.0.1 10.0.0.2"
sudo nmcli connection down "Wired connection 1"
sudo nmcli connection up "Wired connection 1"systemd-resolved not running:
sudo systemctl enable --now systemd-resolved
sudo systemctl restart systemd-resolvedStale cache:
resolvectl flush-cachesDNSSEC chain broken:
Identify the broken link with dig +trace +dnssec example.com. Either fix the chain or temporarily disable
validation.
/etc/resolv.conf overwritten by DHCP:
Configure DHCP client to preserve your nameservers (see the /etc/resolv.conf lesson).
Step 9: Verify
After the fix:
dig example.com
getent hosts example.com
curl -I https://example.comAll three should agree and succeed.
Step 10: Document
Write a one-paragraph summary:
- Symptom
- Failing layer (local resolver, upstream, authoritative)
- Fix applied
- Root cause (if identified)
- Recommendation for prevention
Common patterns
| Failure | Most likely cause |
|---|---|
| NXDOMAIN for a known name | Stale cache, wrong zone, typo |
| SERVFAIL | DNSSEC chain broken, upstream failure |
| Timeout | Upstream resolver unreachable, firewall blocking |
| Connection refused on 53 | Local resolver down or port blocked |
| Some hosts fail, others work | Stale cache on failing hosts only |
| Small answers resolve, large ones time out | Transport, not data: large/fragmented UDP dropped or TCP/53 blocked. Isolate with +notcp +bufsize=4096 versus +tcp |
Escalation
Escalate when:
- The fix involves changing authoritative DNS for a production zone.
- The root cause is not identified within 30 minutes.
- The same failure has occurred twice in a week.
Bring: symptom, evidence (logs from the incident capture), fix tried, hypothesis.