How to Configure the DNS Resolver in Linux

how to configure the DNS resolver in Linux

Whenever a Linux machine needs to turn a domain name like github.com into an IP address, it uses something called the DNS resolver. The resolver is the client-side component responsible for asking DNS servers questions and handing back answers to applications like your browser, curl, ping, or ssh.

Unlike a full DNS server (like BIND), the resolver on a typical Linux machine doesn’t store zone files or serve authoritative answers — it simply asks upstream DNS servers and returns the result. Understanding how to configure it properly is one of the most fundamental Linux networking skills.

This guide walks through resolver configuration from the ground up — covering legacy methods, modern systemd-based methods, and how to troubleshoot resolver problems.


What Is a DNS Resolver?

A DNS resolver (also called a “stub resolver”) is a small piece of software built into the operating system’s networking stack. Its job is:

  1. Accept a hostname lookup request from an application.
  2. Send a DNS query to one or more configured nameservers.
  3. Wait for the response.
  4. Return the resolved IP address (or an error) to the requesting application.
flowchart LR
    A[Application: browser, curl, ssh] --> B[Stub Resolver on Linux]
    B --> C[Configured DNS Server]
    C --> B
    B --> A

The resolver itself usually does not cache — that’s a separate job, often handled by systemd-resolved, nscd, or dnsmasq on modern systems.


The Classic Way: /etc/resolv.conf

For decades, the file /etc/resolv.conf has been the primary way Linux systems learn which DNS servers to use.

Example File

nameserver 8.8.8.8
nameserver 1.1.1.1
search example.com
options timeout:2 attempts:3

Directive Breakdown

DirectiveMeaning
nameserverIP address of a DNS server to query. You can list up to 3.
searchDomain suffixes automatically appended to unqualified hostnames (e.g., ping server1 becomes server1.example.com).
options timeoutHow long (seconds) to wait for a response before retrying.
options attemptsHow many times to retry a query before giving up.

Editing It Manually

sudo nano /etc/resolv.conf

⚠️ Important: On many modern distributions, this file is auto-generated and any manual edits get overwritten on reboot or network restart. We’ll cover how to make changes persistent below.


Modern Linux: systemd-resolved

Most current distributions (Ubuntu 18.04+, Fedora, RHEL 8+) use systemd-resolved as the resolver management service. It provides local caching, DNSSEC validation, and per-interface DNS configuration — features the old static file never had.

Checking If It’s Active

systemctl status systemd-resolved

How It Works

flowchart TD
    A[Application] --> B[systemd-resolved local stub 127.0.0.53]
    B -->|cache miss| C[Real upstream DNS server]
    C --> B
    B -->|cached| A

With systemd-resolved active, /etc/resolv.conf is often a symlink pointing to:

/run/systemd/resolve/stub-resolv.conf

This file typically just contains:

nameserver 127.0.0.53
options edns0 trust-ad

The real upstream DNS servers are managed separately and can be viewed with:

resolvectl status

Setting DNS Servers with systemd-resolved

To set DNS servers for a specific interface (e.g., eth0):

sudo resolvectl dns eth0 1.1.1.1 8.8.8.8
sudo resolvectl domain eth0 example.com

To make this permanent, use netplan (Ubuntu) or NetworkManager, described next.


Configuring DNS via Netplan (Ubuntu Server)

Netplan configuration files live in /etc/netplan/. A typical file:

network:
  version: 2
  ethernets:
    eth0:
      addresses:
        - 192.168.1.50/24
      nameservers:
        addresses:
          - 1.1.1.1
          - 8.8.8.8
        search:
          - example.com
      routes:
        - to: default
          via: 192.168.1.1

Apply the configuration:

sudo netplan apply

Configuring DNS via NetworkManager (Desktop Linux / RHEL)

If your system uses NetworkManager (common on desktops and RHEL-based servers):

nmcli con show                              # list connections
nmcli con mod "Wired connection 1" ipv4.dns "1.1.1.1 8.8.8.8"
nmcli con mod "Wired connection 1" ipv4.ignore-auto-dns yes
nmcli con up "Wired connection 1"

Verify:

nmcli device show eth0 | grep DNS

Configuring DNS via Static Network Scripts (Older RHEL/CentOS)

On older RHEL/CentOS systems using the legacy network service:

sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0

Add or modify:

DNS1=1.1.1.1
DNS2=8.8.8.8
DOMAIN="example.com"
PEERDNS=no

Restart networking:

sudo systemctl restart network

Comparison Table: Resolver Configuration Methods

MethodDistro Typical UsePersistent?Local Caching?Notes
/etc/resolv.conf manual editLegacy systems, containersNo (often overwritten)NoSimple but fragile
systemd-resolvedUbuntu 18.04+, Fedora, RHEL 8+YesYesModern default
NetplanUbuntu Server 18.04+YesDepends on backendYAML-based
NetworkManager (nmcli)Desktops, RHELYesOptionalGUI + CLI support
ifcfg-* scriptsRHEL/CentOS 6/7YesNoLegacy but still common
dnsmasqHome routers, small networksYesYesLightweight, DHCP+DNS combo

Real-World Example: Multi-Interface Server

Imagine a Linux server with two network interfaces — one connected to a public internet uplink (eth0) and one to an internal management network (eth1). You may want DNS queries for internal hostnames to go to your internal DNS server, and everything else to a public resolver.

With systemd-resolved, this is done with per-link DNS + domain routing:

sudo resolvectl dns eth1 10.0.0.5
sudo resolvectl domain eth1 "~corp.internal"
sudo resolvectl dns eth0 1.1.1.1
sudo resolvectl domain eth0 "~."

The ~corp.internal syntax tells the resolver: “route any query ending in corp.internal through this interface’s DNS server,” while ~. is a catch-all for everything else via eth0.


Cisco Example: DNS Resolver Settings on IOS

Cisco devices have their own resolver settings, conceptually similar to a Linux client:

ip domain name example.com
ip name-server 1.1.1.1
ip name-server 8.8.8.8
ip domain lookup

Test resolution directly from the Cisco CLI:

ping www.example.com

If ip domain lookup is disabled, unqualified commands typed at the CLI won’t trigger accidental DNS lookups — a common gotcha for new network engineers who mistype a command and then wait for a long DNS timeout.


Python Example: Using the System Resolver

Python applications typically use the operating system’s resolver settings automatically via socket:

import socket

try:
    ip = socket.gethostbyname('www.example.com')
    print(f"Resolved IP: {ip}")
except socket.gaierror as e:
    print(f"Resolution failed: {e}")

For more control (e.g., specifying a custom DNS server rather than the system default), use dnspython:

import dns.resolver

resolver = dns.resolver.Resolver()
resolver.nameservers = ['1.1.1.1']

answer = resolver.resolve('www.example.com', 'A')
for rdata in answer:
    print(rdata.address)

Testing Your Resolver Configuration

# Check what resolver Linux is actually using
cat /etc/resolv.conf

# Query using the resolver's default settings
getent hosts www.example.com

# Detailed status when using systemd-resolved
resolvectl status

# Manual query bypassing the OS resolver entirely
dig @1.1.1.1 www.example.com

Best Practices

  • Use at least two nameservers for redundancy — if one is unreachable, the second is tried automatically.
  • Prefer systemd-resolved or NetworkManager on modern systems rather than hand-editing /etc/resolv.conf, since manual edits are often lost on reboot.
  • Set a search domain carefully — an overly broad search list can cause slow or incorrect lookups for typos.
  • Match internal and external DNS carefully in split-DNS environments to avoid leaking internal hostnames externally.
  • Use DNS servers close to your network (geographically and topologically) to minimize latency.
  • Enable DNSSEC validation where supported for extra protection against spoofed responses.

Troubleshooting

SymptomLikely CauseFix
Name or service not knownNo nameservers configured or unreachableCheck /etc/resolv.conf / resolvectl status
Resolution works with dig @8.8.8.8 but not with plain digLocal resolver misconfiguredVerify /etc/resolv.conf points to a working server
Changes to /etc/resolv.conf disappear after rebootFile is auto-managed by systemd-resolved/NetworkManagerConfigure DNS via resolvectl, nmcli, or netplan instead
Slow lookupsDNS server far away or overloaded, or search domain causing multiple lookups per querySwitch to a faster resolver; simplify search list
Internal hostnames not resolvingSplit-DNS not configured correctlySet per-domain DNS routing with resolvectl domain
Temporary failure in name resolutionNetwork interface down or DNS server unreachableCheck connectivity: ping <dns_server_ip>

Understanding Resolver Order and Failover Behavior

When a Linux resolver has multiple nameservers configured, it doesn’t load-balance between them — it tries them in order. The first nameserver listed is queried first; only if it fails to respond within the configured timeout does the resolver move on to the next one in the list.

nameserver 10.0.0.5
nameserver 1.1.1.1

In this example, every query is attempted against 10.0.0.5 first. If that server is slow or down, there’s a timeout penalty (controlled by options timeout:N) before the resolver falls back to 1.1.1.1. This is worth knowing because a “half-broken” primary DNS server — one that’s up but not responding — can actually make name resolution slower than if it were fully down, since every query pays the timeout cost before failing over.

sequenceDiagram
    participant App as Application
    participant Resolver as Stub Resolver
    participant DNS1 as Primary DNS 10.0.0.5
    participant DNS2 as Secondary DNS 1.1.1.1

    App->>Resolver: Resolve hostname
    Resolver->>DNS1: Query
    Note over Resolver,DNS1: Timeout (no response)
    Resolver->>DNS2: Query (fallback)
    DNS2-->>Resolver: Answer
    Resolver-->>App: Answer

The Role of /etc/hosts and nsswitch.conf

Before any resolver ever sends a query out onto the network, Linux checks a local static file: /etc/hosts. This file lets you hard-code specific name-to-IP mappings that bypass DNS entirely.

127.0.0.1   localhost
192.168.1.20  devserver.local

Whether /etc/hosts is checked before or after DNS — and in what order various other sources like NIS or LDAP are consulted — is controlled by /etc/nsswitch.conf:

hosts: files dns

This line means: “check /etc/hosts (files) first, then fall back to DNS.” This order is why adding an entry to /etc/hosts immediately overrides whatever DNS would otherwise return — useful for local testing, and a very common source of confusion when someone forgets they added a temporary entry months ago and can’t figure out why a hostname “won’t update.”

Testing Resolver Behavior Systematically

A methodical approach to resolver testing separates local overrides, DNS caching layers, and actual upstream DNS server behavior:

# 1. Check for local hosts file override
grep -i example.com /etc/hosts

# 2. Check the order of resolution sources
cat /etc/nsswitch.conf | grep hosts

# 3. Test resolution via the full OS stack
getent hosts www.example.com

# 4. Test resolution via the configured resolver directly
cat /etc/resolv.conf
dig www.example.com

# 5. Bypass everything and test the upstream server directly
dig @8.8.8.8 www.example.com

Running through these five layers in order will almost always reveal exactly where a resolution mismatch is occurring — whether it’s a stale hosts file entry, a caching layer, or the upstream DNS server itself giving an unexpected answer.

Comparison: Resolver Behavior Across Common Distributions

DistributionDefault Resolver ManagerLocal Caching by Default?Typical /etc/resolv.conf Owner
Ubuntu 20.04+systemd-resolvedYesSymlink to systemd-resolved stub
Debian 11+systemd-resolved (or manual)Depends on installVaries
Fedora / RHEL 8+systemd-resolved / NetworkManagerYesSymlink or managed by NetworkManager
RHEL/CentOS 7Legacy network scriptsNoDirectly written by DHCP client
Alpine Linux (containers)Minimal, often staticNoDirectly written, static
Docker containersInherited from host or --dns flagNoSet at container creation

Docker and Container DNS Resolution

Containers deserve special mention because their DNS resolution model often surprises people coming from traditional servers. By default, Docker containers get their /etc/resolv.conf populated based on the Docker daemon’s own configuration — not automatically inherited from complex host resolver setups like systemd-resolved.

# Run a container with a custom DNS server<br>docker run --dns=1.1.1.1 --dns=8.8.8.8 alpine nslookup example.com<

For Docker Compose environments, DNS can be set per-service:

services:
  app:
    image: myapp
    dns:
      - 1.1.1.1
      - 8.8.8.8

This matters because a container silently using an unreachable or unexpected DNS server is a very common source of “works on my machine but not in the container” bugs.

Frequently Asked Questions

Why does editing /etc/resolv.conf sometimes get reverted automatically? Because on most modern systems, that file is actively managed by systemd-resolved, NetworkManager, or a DHCP client — any of which will overwrite manual edits the next time they run. Always configure DNS through the tool that’s actually managing the file (resolvectl, nmcli, or your DHCP/netplan config) rather than editing it directly.

Is it safe to just always use public DNS servers like 1.1.1.1 or 8.8.8.8? For general internet resolution, yes — these are fast, reliable, privacy-respecting options. However, they cannot resolve your internal/private hostnames (like fileserver.corp.local), so environments with internal DNS zones need a resolver that’s aware of those internal domains, either directly or via split-DNS routing.

What’s the difference between a resolver timing out and returning NXDOMAIN? A timeout means the resolver never got a response at all — the server is unreachable or too slow. NXDOMAIN means the server responded promptly, but explicitly said “this name does not exist.” These point to very different problems: timeouts suggest network/server issues, while NXDOMAIN suggests a naming/zone configuration issue.

Summary

The DNS resolver is the unsung workhorse behind almost every network operation on a Linux machine. Whether you’re editing the classic /etc/resolv.conf, managing things through systemd-resolved, or using Netplan/NetworkManager on modern distributions, understanding exactly how your system decides which DNS server to ask — and in what order — is essential for building both reliable and secure Linux systems.


Further Reading

Total
2
Shares

Leave a Reply

Previous Post
how to use DNS utility programs in Linux

How to Use DNS Utility Programs in Linux

Next Post
how to configure a caching name server in Linux

How to Configure a Caching Name Server in Linux

Related Posts