$linuxjunkies
>

Linux DNS Configuration

Configure Linux DNS end-to-end: understand /etc/resolv.conf, manage systemd-resolved, use /etc/hosts for static overrides, and verify with dig.

IntermediateUbuntuDebianFedoraArch9 min readUpdated June 7, 2026

Before you start

  • sudo or root access on the target system
  • Basic familiarity with a terminal text editor (nano, vim)
  • The dnsutils or bind-utils package installed for dig

DNS configuration on Linux has two layers that confuse even experienced admins: the file /etc/resolv.conf and the resolver daemon sitting in front of it. On modern systems that daemon is systemd-resolved, which manages a local stub resolver, caching, and per-link DNS settings — while /etc/resolv.conf often becomes a symlink rather than a real file. This guide walks through both layers, shows you how /etc/hosts fits in, and gives you concrete tools to verify everything is working.

How Linux Resolves Names

Name resolution order is controlled by /etc/nsswitch.conf. The relevant line almost always reads:

grep hosts /etc/nsswitch.conf

You will see something like hosts: files dns myhostname. This means the kernel checks /etc/hosts first (files), then a DNS resolver (dns), then systemd-resolved's hostname logic (myhostname). Understanding this order prevents hours of debugging surprises.

/etc/hosts — Static Overrides

Before any DNS query leaves your machine, the resolver checks /etc/hosts. It is a flat text file: one IP address per line followed by one or more hostnames.

cat /etc/hosts

A minimal hosts file looks like this (output will vary):

127.0.0.1   localhost
127.0.1.1   myhostname.local myhostname
::1         localhost ip6-localhost ip6-loopback

Add a static override by appending a line. For example, to point dev.example.com at a local VM:

echo '192.168.1.50  dev.example.com' | sudo tee -a /etc/hosts

Changes take effect immediately — no service restart needed. Remove the line when you no longer need it; stale entries are a common source of mysterious failures.

Understanding /etc/resolv.conf

/etc/resolv.conf tells the C library resolver (used by almost every program) which nameservers to query and what search domains to append. A traditional hand-edited file looks like:

nameserver 1.1.1.1
nameserver 8.8.8.8
search example.com

On modern distros, however, this file is usually a symlink managed by systemd-resolved or NetworkManager. Editing it directly will either be overwritten on next network event or have no effect at all. Check what you actually have:

ls -la /etc/resolv.conf

Common targets you may see:

  • /run/systemd/resolve/stub-resolv.conf — the stub mode used by most Ubuntu and Debian systems; points to 127.0.0.53
  • /run/systemd/resolve/resolv.conf — the uplink mode; lists the actual upstream servers
  • /run/NetworkManager/resolv.conf — NetworkManager is managing DNS directly
  • A regular file — either a container/VM environment or a manually managed server

systemd-resolved

systemd-resolved is the recommended resolver on systemd-based distros. It provides a local stub at 127.0.0.53:53, caches responses, validates DNSSEC (optionally), and applies per-link DNS configuration pushed by NetworkManager or networkd.

Check Status

resolvectl status

This shows the global DNS servers, the per-link servers, DNSSEC mode, and cache hits. Pay attention to the Current DNS Server line for each interface.

Enable and Start (if not already running)

On most distros it ships enabled. If not:

sudo systemctl enable --now systemd-resolved

Then symlink /etc/resolv.conf to the stub file:

sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

Set Global DNS Servers

Edit (or create) /etc/systemd/resolved.conf and set your preferred servers:

sudo nano /etc/systemd/resolved.conf

Relevant options under [Resolve]:

[Resolve]
DNS=1.1.1.1 1.0.0.1
FallbackDNS=8.8.8.8 8.8.4.4
Domains=~.
DNSSEC=allow-downgrade
DNSOverTLS=opportunistic

Domains=~. makes this the resolver for all domains (the wildcard routing domain). Restart after changes:

sudo systemctl restart systemd-resolved

If you manage interfaces with systemd-networkd instead of NetworkManager, set DNS per interface in /etc/systemd/network/20-wired.network:

[Match]
Name=eth0

[Network]
DHCP=yes
DNS=192.168.1.1

Distro Differences

Fedora / RHEL 9+ / Rocky 9+ default to NetworkManager managing DNS. NetworkManager can forward to systemd-resolved or write /etc/resolv.conf itself. Check the active plugin:

NetworkManager --print-config | grep dns

To hand control to systemd-resolved, add to /etc/NetworkManager/conf.d/dns.conf:

[main]
dns=systemd-resolved
sudo systemctl restart NetworkManager

Arch Linux ships neither resolved nor NetworkManager enabled by default; enable whichever you choose after installation.

Ubuntu 20.04+ enables systemd-resolved by default with the stub symlink already in place — no manual setup needed on a fresh install.

Testing DNS with dig

dig is the most reliable DNS troubleshooting tool. Install it if needed:

# Debian/Ubuntu
sudo apt install dnsutils

# Fedora/RHEL
sudo dnf install bind-utils

# Arch
sudo pacman -S bind

Basic Lookup

dig linux.org

Look for the ANSWER SECTION and the SERVER line at the bottom. The server line tells you which resolver actually answered — this is critical when diagnosing cache or stub issues.

Query a Specific Nameserver

Bypass the system resolver and query directly:

dig @1.1.1.1 linux.org

Query the systemd-resolved Stub

dig @127.0.0.53 linux.org

If this works but dig linux.org does not, your /etc/resolv.conf is not pointing at the stub.

Reverse Lookup

dig -x 1.1.1.1

Check DNSSEC

dig +dnssec linux.org

Look for the ad flag (authenticated data) in the flags line to confirm DNSSEC validation succeeded.

Flush the resolved Cache

When troubleshooting stale records:

resolvectl flush-caches

Verification Checklist

  1. Run resolvectl status and confirm a valid upstream DNS server appears for your active interface.
  2. Run dig @127.0.0.53 linux.org — you should get an answer in under 100 ms.
  3. Run dig linux.org without specifying a server — the result should match the above.
  4. Check cat /etc/resolv.conf points to nameserver 127.0.0.53 (stub mode) or a valid external IP.
  5. Test a hostname from /etc/hosts: getent hosts dev.example.com should return the IP you set.

Troubleshooting

SymptomLikely CauseFix
dig times out at 127.0.0.53systemd-resolved not runningsudo systemctl start systemd-resolved
DNS works in terminal, fails in browserMDNS or DNS-over-HTTPS in browser overriding system DNSDisable DoH in browser settings or check MDNS firewall rules
Edits to resolv.conf disappearNetworkManager or networkd overwrites on link-upConfigure DNS through NetworkManager or systemd-resolved, not the file directly
NXDOMAIN for internal hostnamesSearch domain not setAdd Domains=yourdomain.internal in resolved.conf or via DHCP option 15
Slow resolution (200ms+)Resolver falling back to secondary after primary timeoutCheck resolvectl statistics for timeouts; switch primary nameserver
tested on:Ubuntu 24.04Debian 12Fedora 40Arch 2024.05

Frequently asked questions

Why does my /etc/resolv.conf keep getting overwritten?
NetworkManager or systemd-networkd rewrites it on every link-up event. Configure DNS through those tools instead of editing the file directly, or lock it with 'chattr +i' as a last resort on static servers.
What is the difference between /run/systemd/resolve/stub-resolv.conf and /run/systemd/resolve/resolv.conf?
The stub file points to 127.0.0.53 (the local resolved daemon). The non-stub file lists actual upstream nameservers. Use the stub version so resolved can cache and apply per-link settings.
Can I use systemd-resolved and a local DNS server like dnsmasq together?
Yes. Configure dnsmasq to listen on a different port or address, and set it as the upstream in resolved.conf using the DNS= directive, or disable resolved and let dnsmasq write resolv.conf directly.
Does /etc/hosts work for IPv6 addresses?
Yes. Add a line starting with the full IPv6 address followed by the hostname, for example '::1 localhost'. The resolver checks it the same way it checks IPv4 entries.
How do I set a per-connection DNS server in NetworkManager without editing config files?
Use 'nmcli con mod <connection-name> ipv4.dns "1.1.1.1 8.8.8.8" ipv4.ignore-auto-dns yes' then reconnect. NetworkManager will pass those servers to systemd-resolved automatically.

Related guides