DNS Guide

The Domain Name System translates hostnames to IP addresses and back. On Linux the resolver library reads /etc/resolv.conf to find upstream nameservers, but modern systems layer systemd-resolved on top for caching and split-DNS support. This guide covers client-side resolution, the essential query tools (dig, nslookup, host), running BIND9 as an authoritative nameserver, and setting up Unbound as a local caching resolver.

Back to the Networking hub. Related guides: Network Configuration | DHCP & DNS Server.

/etc/resolv.conf

The traditional resolver configuration file. It lists up to three nameservers, a search domain, and optional behaviour flags:

# /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
search example.com internal.example.com
options timeout:2 attempts:3 rotate

When systemd-resolved is active this file is usually a symlink to /run/systemd/resolve/stub-resolv.conf which points at the local stub listener 127.0.0.53.

# Check what resolv.conf points to
ls -l /etc/resolv.conf

# See the actual upstream servers resolved is using
resolvectl status

systemd-resolved (resolvectl)

systemd-resolved provides a caching stub resolver, DNSSEC validation, and per-link DNS settings. It replaced resolvconf on most systemd-based distributions.

# Show current DNS configuration per interface
resolvectl status

# Query a record through resolved
resolvectl query example.com

# Set DNS for a specific link
resolvectl dns eth0 1.1.1.1 9.9.9.9

# Set the search domain for a link
resolvectl domain eth0 example.com

# Flush the local cache
resolvectl flush-caches

# View cache statistics
resolvectl statistics

dig

dig (Domain Information Groper) is the Swiss-army knife of DNS debugging. It comes from the bind-utils or dnsutils package.

# Simple A record lookup
dig example.com

# Query a specific record type
dig example.com MX
dig example.com NS
dig example.com AAAA
dig example.com TXT

# Query a specific nameserver
dig @8.8.8.8 example.com A

# Short answer only
dig +short example.com A

# Trace the delegation chain from the root
dig +trace example.com

# Reverse lookup
dig -x 93.184.216.34

# Show all common records
dig example.com ANY +noall +answer

nslookup and host

These simpler tools are useful for quick lookups:

# nslookup
nslookup example.com
nslookup -type=MX example.com
nslookup example.com 8.8.8.8    # use a specific server

# host
host example.com
host -t MX example.com
host 93.184.216.34               # reverse lookup

Running BIND9 as an authoritative nameserver

BIND9 is the most widely deployed DNS server software. Install it and configure a forward zone:

sudo apt install bind9 bind9-utils   # Debian / Ubuntu
sudo dnf install bind bind-utils      # RHEL / Fedora

named.conf (simplified)

// /etc/bind/named.conf.local
zone "example.lan" {
    type master;
    file "/etc/bind/db.example.lan";
    allow-transfer { 10.0.0.2; };     // secondary NS
};

zone "0.0.10.in-addr.arpa" {
    type master;
    file "/etc/bind/db.10.0.0";
};

Zone file

; /etc/bind/db.example.lan
$TTL 86400
@   IN  SOA ns1.example.lan. admin.example.lan. (
        2025040101  ; serial  (YYYYMMDDNN)
        3600        ; refresh
        900         ; retry
        1209600     ; expire
        86400 )     ; negative-cache TTL

    IN  NS  ns1.example.lan.
    IN  NS  ns2.example.lan.

ns1 IN  A   10.0.0.1
ns2 IN  A   10.0.0.2
www IN  A   10.0.0.10
db  IN  A   10.0.0.20
# Check the zone file syntax
named-checkzone example.lan /etc/bind/db.example.lan

# Check the main configuration
named-checkconf

# Reload after changes
sudo rndc reload

Unbound as a caching resolver

Unbound is a lightweight, security-oriented caching resolver. It is an excellent choice for a local network resolver that forwards to upstream servers or performs full recursion.

sudo apt install unbound        # Debian / Ubuntu
sudo dnf install unbound        # RHEL / Fedora
# /etc/unbound/unbound.conf (key excerpts)
server:
    interface: 0.0.0.0
    access-control: 10.0.0.0/8 allow
    access-control: 127.0.0.0/8 allow
    do-ip6: no

    # Performance tuning
    num-threads: 2
    msg-cache-size: 64m
    rrset-cache-size: 128m

    # DNSSEC: auto-trust-anchor-file ships root keys
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

    # Local records (like /etc/hosts but served via DNS)
    local-zone: "example.lan." static
    local-data: "gateway.example.lan. A 10.0.0.1"
    local-data: "nas.example.lan.     A 10.0.0.50"

# Forward to upstream (optional -- remove for full recursion)
forward-zone:
    name: "."
    forward-addr: 1.1.1.1
    forward-addr: 9.9.9.9
# Test the configuration
unbound-checkconf

# Start and enable
sudo systemctl enable --now unbound

# Query through unbound
dig @127.0.0.1 example.com