DNS resolution on a Linux server is a multi-layered system. When an application calls getaddrinfo("example.com"), the request passes through the Name Service Switch (NSS) framework, which consults sources in the order defined in /etc/nsswitch.conf — typically /etc/hosts first, then a DNS resolver. The DNS resolver reads its configuration from /etc/resolv.conf, which lists the DNS servers and search domains. On RHEL 9, NetworkManager manages /etc/resolv.conf dynamically and can overwrite manual changes on interface up/down events. Understanding all three layers — NSS, /etc/hosts, and /etc/resolv.conf — and how NetworkManager interacts with them is essential for correctly configuring DNS on any RHEL 9 server.

This guide covers configuring /etc/hosts for local resolution, managing /etc/resolv.conf both manually and through NetworkManager, setting per-interface DNS servers and search domains, testing and troubleshooting DNS resolution, and configuring a local caching resolver with systemd-resolved.

Prerequisites

  • RHEL 9 server with root or sudo access
  • NetworkManager running (default on RHEL 9)

Step 1 — Understand the Resolution Order with nsswitch.conf

The file /etc/nsswitch.conf defines the order in which name resolution sources are consulted:

cat /etc/nsswitch.conf | grep hosts
hosts: files dns myhostname

This means:

  1. files — check /etc/hosts first
  2. dns — query DNS servers from /etc/resolv.conf
  3. myhostname — resolve the server’s own hostname via systemd

Change the order only if you have a specific reason (e.g., in containerised environments where DNS must take precedence over hosts file).

Step 2 — Configure /etc/hosts

The /etc/hosts file provides static name-to-IP mappings that bypass DNS entirely. It is read first for every DNS lookup (per the files entry in nsswitch.conf):

vi /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

# Server's own FQDN (must use actual IP, not 127.0.0.1)
203.0.113.10  web01.example.com web01

# Internal cluster members (avoids DNS dependency for critical services)
10.0.0.5      db01.internal.example.com db01
10.0.0.6      db02.internal.example.com db02
10.0.0.10     cache01.internal.example.com cache01

Rules for /etc/hosts:

  • The FQDN must come before the short name on the same line
  • Use the server’s actual IP address for its own entry (not loopback)
  • Changes take effect immediately — no restart needed
  • Entries here override DNS for the same name

Step 3 — Understand /etc/resolv.conf and NetworkManager

On RHEL 9, NetworkManager manages /etc/resolv.conf. When a network interface comes up, NetworkManager rewrites the file with DNS settings from the interface configuration. Manual edits to /etc/resolv.conf will be overwritten on the next network event.

# Check if resolv.conf is managed by NetworkManager
ls -la /etc/resolv.conf    # May be a symlink

# View current content
cat /etc/resolv.conf

A typical /etc/resolv.conf:

# Generated by NetworkManager
search example.com internal.example.com
nameserver 8.8.8.8
nameserver 8.8.4.4

Step 4 — Configure DNS via NetworkManager (Persistent)

To set DNS servers that survive reboots and interface resets, configure them through NetworkManager:

# List connections
nmcli connection show

# Show DNS settings for a specific connection
nmcli connection show "System eth0" | grep -i dns

# Set DNS servers for a connection
nmcli connection modify "System eth0" ipv4.dns "1.1.1.1 8.8.8.8"

# Set DNS search domains
nmcli connection modify "System eth0" ipv4.dns-search "example.com internal.example.com"

# Disable automatic DNS from DHCP and use only the manually specified ones
nmcli connection modify "System eth0" ipv4.ignore-auto-dns yes

# Apply changes
nmcli connection up "System eth0"

# Verify
cat /etc/resolv.conf

Step 5 — Add DNS Settings to Multiple Interfaces

Servers with multiple NICs (e.g., public-facing eth0 and private backend eth1) need separate DNS configurations:

# Public interface — use public resolvers
nmcli connection modify "System eth0" ipv4.dns "1.1.1.1 8.8.8.8"
nmcli connection modify "System eth0" ipv4.dns-search "example.com"

# Backend interface — use internal resolver for private domains
nmcli connection modify "System eth1" ipv4.dns "10.0.0.1"
nmcli connection modify "System eth1" ipv4.dns-search "internal.example.com"

# Set DNS priority (lower number = higher priority)
nmcli connection modify "System eth0" ipv4.dns-priority 10
nmcli connection modify "System eth1" ipv4.dns-priority 50

nmcli connection up "System eth0"
nmcli connection up "System eth1"

Step 6 — Configure /etc/resolv.conf Options

The options directive in /etc/resolv.conf tunes resolver behaviour. Set these via NetworkManager using the ipv4.dns-options property, or write a static resolv.conf (see Step 7):

options ndots:5 timeout:2 attempts:3 rotate
  • ndots:5 — names with fewer than 5 dots are tried with search domains appended first
  • timeout:2 — timeout per DNS server query attempt (seconds)
  • attempts:3 — retry count per server
  • rotate — rotate between nameservers instead of always trying the first one first (improves load distribution)

Step 7 — Make resolv.conf Static (Bypass NetworkManager)

In some environments (containers, static server builds), you want a static /etc/resolv.conf that NetworkManager never touches:

# Tell NetworkManager not to manage resolv.conf
vi /etc/NetworkManager/conf.d/no-resolv.conf
[main]
dns=none
systemctl reload NetworkManager

# Now write a static resolv.conf
vi /etc/resolv.conf
search example.com
nameserver 1.1.1.1
nameserver 8.8.8.8
options timeout:2 attempts:3 rotate
# Protect it from accidental overwrites
chattr +i /etc/resolv.conf    # Makes the file immutable
lsattr /etc/resolv.conf       # Verify

Step 8 — Enable systemd-resolved for Local DNS Caching

systemd-resolved provides a local caching DNS stub resolver (127.0.0.53), which dramatically speeds up repeated DNS lookups and handles per-interface DNS routing:

systemctl enable --now systemd-resolved

# Point resolv.conf at the stub resolver
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

# Configure DNS in /etc/systemd/resolved.conf
vi /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1 8.8.8.8
FallbackDNS=9.9.9.9
Domains=example.com
DNSSEC=yes
DNSOverTLS=opportunistic
Cache=yes
systemctl restart systemd-resolved

# Check resolution status
resolvectl status

Step 9 — Test and Troubleshoot DNS Resolution

# Basic forward lookup
host example.com
nslookup example.com
dig example.com

# Query a specific DNS server directly (bypass resolv.conf)
dig @8.8.8.8 example.com

# Reverse lookup (PTR record)
dig -x 93.184.216.34

# Check which DNS server is being used
dig example.com | grep SERVER

# Test the search domain (short name resolution)
host db01    # Should resolve to 10.0.0.5 if search=internal.example.com

# Flush systemd-resolved cache
resolvectl flush-caches

# Show DNS cache statistics
resolvectl statistics

# Trace the full resolution path
dig +trace example.com

Verification Checklist

# Current resolv.conf
cat /etc/resolv.conf

# NSS order
grep hosts /etc/nsswitch.conf

# NetworkManager DNS config
nmcli connection show "System eth0" | grep -i dns

# Test resolution
getent hosts example.com
getent hosts db01

Troubleshooting

  • DNS stops working after reboot — NetworkManager is overwriting your manual /etc/resolv.conf. Configure DNS through nmcli (Step 4) or use dns=none in NetworkManager config (Step 7).
  • Short names not resolving — check the search directive in /etc/resolv.conf and the ndots option. The search domain must be set.
  • Slow DNS lookupssystemd-resolved with caching (Step 8) eliminates repeated lookups. Also check for failed first-server queries causing timeouts: reduce timeout in resolv.conf options.

Conclusion

Your RHEL 9 server now has a correctly layered DNS configuration: static entries in /etc/hosts for critical internal hosts, persistent DNS server configuration through NetworkManager, and optionally a local caching resolver via systemd-resolved. You understand the resolution order and can diagnose failures at each layer.

Next steps: How to Use rsync for Efficient File Synchronisation on RHEL 9, How to Configure the Firewall on RHEL 9, and How to Set a Hostname and FQDN on RHEL 9.