Tune DNS Lookups Safely with resolv.conf
You edited /etc/resolv.conf, DNS worked, and an hour later your change had vanished; that file often belongs to someone else. You will find out who owns it, understand the settings that shape ordinary lookups and change it only when this machine really owns it. Allow about 15 minutes.
The route
Jump straight to the step you need, or tick off Done means at the end.
- You need: a shell and the installed
resolv.conf(5)manpage. - Administrator access: only if you are changing a system-managed file.
1. Check which file you are really using
/etc/resolv.conf is the conventional path, but it is often a symbolic link generated by NetworkManager, systemd-resolved, a container runtime or another network manager. Look before you touch:
$ ls -l /etc/resolv.conf
$ readlink -f /etc/resolv.conf
$ sed -n '1,80p' /etc/resolv.conf
On the machine used for this guide, the link points into /run/systemd/resolve and the file says it is dynamic. Editing it directly would be temporary at best and could fight the service that owns it, so change that manager's settings instead.
Warning
Do not replace a symbolic link with a regular file until you have identified the manager and planned a rollback.
Checkpoint
Record the output of readlink -f. Under /run means generated. If ls -l shows a regular file, carry on, but still check whether a package or service rewrites it.
2. Read the current settings
The file is line-oriented. A keyword starts the line, followed by whitespace and its value. Lines starting with # or ; are comments. These are the settings that affect most hosts:
nameserver 192.0.2.53
nameserver 2001:db8::53
search office.example.test dev.example.test
options ndots:1 timeout:2 attempts:2 rotate
Those addresses are documentation placeholders, not usable DNS servers.
nameservertakes an IPv4 or IPv6 address, up to three entries. With none at all, the resolver falls back to the local machine.- Order matters. Multiple servers are tried in order when a query times out.
rotatespreads queries across the listed servers instead of always starting with the first.searchapplies to names with fewer dots than thendotsthreshold. With the defaultndots:1, a name containing a dot is tried as an absolute name first; a bare name likeprintercan then be tried with each suffix.- Keep the search list short. Long or remote lists add traffic and delay, so include only domains you actually use.
- Last
searchline wins if there are several. The olderdomainkeyword handles one search entry and is obsolete.
3. Choose timeout and retry values deliberately
The main numeric controls are timeout:n and attempts:n. On this glibc 2.39 system the documented defaults are five seconds and two attempts, and the resolver silently caps them at 30 seconds and five attempts.
They are per-resolver controls, not a promise that one application call finishes within timeout seconds: a single call can query several servers and do more than one lookup.
Example
This small, explicit setting makes a workstation fail faster when its DNS service is down.
options timeout:2 attempts:2
- Do not hide a flaky network behind a tiny timeout. It turns brief packet loss into application failures.
- Keep
ndotslow unless you have a specific internal naming scheme. A high value can make a short name generate many search-domain queries before it is tried as an absolute name.
Checkpoint
Write down the current nameserver, search and options lines before changing anything. That is your quickest recovery reference.
4. Test overrides on one process first
glibc lets a process override the search list with LOCALDOMAIN and amend options with RES_OPTIONS. It is a safe way to try option syntax on one command without touching the system file or any other process:
$ RES_OPTIONS='ndots:2 timeout:1 attempts:1' getent hosts localhost
::1 localhost
$ printf 'exit status: %s\n' "$?"
exit status: 0
Your address may differ. You want exit status zero and a usable localhost entry.
Tip
getent exercises the host lookup path configured by NSS, so it is a practical smoke test, not a packet-level DNS trace. A localhost answer may come from /etc/hosts, so it does not prove an external nameserver is reachable.
To test a search-list override, use a name that should exist in your own DNS domain, not an invented public one:
$ LOCALDOMAIN='YOUR.INTERNAL.DOMAIN' RES_OPTIONS='ndots:2 timeout:2 attempts:1' getent hosts HOSTNAME
Replace both uppercase values with approved internal ones. The variables disappear when the command exits.
Warning
Do not put secrets in these variables, and do not paste an untrusted string into a shell command.
5. Change a static file only with a rollback
Warning
Changing resolver settings can break package downloads, SSH name lookups, monitoring and services. Do it in a maintenance window with an existing shell kept open. If /etc/resolv.conf is a symlink or managed by a service, stop here and change the manager's configuration instead.
For a confirmed static regular file, take a backup, edit with elevated privileges and keep the content minimal:
$ sudo cp --preserve=mode,ownership,timestamps /etc/resolv.conf /etc/resolv.conf.before-dns-change
$ sudoedit /etc/resolv.conf
A typical static file looks like this, using real DNS servers from your network administrator:
nameserver DNS_SERVER_1
nameserver DNS_SERVER_2
search YOUR.INTERNAL.DOMAIN
options timeout:2 attempts:2
- Replace every placeholder. Do not copy the documentation addresses from this guide.
- One line each. Keep each keyword and its value on a single line.
- No familiar-looking suffixes. A search suffix changes where short names are sent, so add one only on purpose.
Undo by restoring the backup, then verify again:
$ sudo cp --preserve=mode,ownership,timestamps /etc/resolv.conf.before-dns-change /etc/resolv.conf
$ sed -n '1,80p' /etc/resolv.conf
Recovery
The backup stays until you remove it. Do not delete it mid-incident; first prove normal lookups work and nothing is rewriting the file.
6. Verify and diagnose
Read the file again, then test a local entry and a name your DNS service should answer:
$ sed -n '1,80p' /etc/resolv.conf
$ getent hosts localhost
$ getent hosts HOSTNAME.YOUR.INTERNAL.DOMAIN
$ printf 'last status: %s\n' "$?"
- Non-zero final status: the name was not resolved through the configured NSS path. Check spelling, server addresses, search suffix and network reachability.
- File has reverted: a manager owns the configuration and will overwrite manual edits.
- Lookups are slow: inspect the search list and
ndotsbefore shrinking timeouts.
Common traps
no-aaaais not an IPv6 fix. It exists in glibc since 2.36 (so in the installed 2.39) as a diagnostic switch. It suppresses DNS AAAA queries, is incompatible with EDNS0 usage and DNSSEC validation by applications, and does not remove IPv6 data from/etc/hosts. Use it only for a controlled investigation with a clear removal plan.trust-adis security-sensitive. Since glibc 2.31 it lets the stub resolver request and preserve the DNSSEC AD bit, but you must trust both the validating resolver and the network path to it. Do not enable it just because a tutorial or copied configuration has it.
Done means
- Owner known: you know whether
/etc/resolv.confis static or managed. - Settings understood: you can explain the active
nameserver,searchandoptionslines. - Tested small first: you tried resolver options per process before any system-wide edit.
- Rollback ready: any static-file change has a dated backup and a tested restore command.
- Lookups work:
getentresolves a local name and an approved DNS name after the change. - Risky options off: diagnostic and trust-sensitive options stay disabled unless you have a documented reason.