DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

Configuring & Changing Setting in DNS server on Linux

— ny_wk

Configuring & Changing Setting in DNS server on Linux

To configure a DNS server on Linux you install BIND (the named daemon), define your zones in /etc/named.conf, write forward and reverse zone files with SOA, NS, A and PTR records, then validate, start, and open the firewall on port 53. This guide walks through a complete, working name server on a modern RHEL, Rocky, AlmaLinux, or CentOS Stream box, then shows how to point any Linux client at it.

A DNS server on Linux turns human-friendly names like www.example.com into IP addresses such as 192.168.10.2, and back again. The Domain Name System is the directory service of the internet: instead of memorizing numeric addresses for every host you visit, you remember a name, and a resolver looks up the address for you. BIND (the Berkeley Internet Name Domain) is the most widely deployed implementation of that service, and its daemon is called named. By the end of this walkthrough you will have an authoritative name server that answers both forward and reverse queries for your own internal domain.

The problem: names vs. numbers

Every host on a network is reachable by an IP address, for example 192.168.10.2. Numbers are easy for machines but hard for people. Think of DNS as a phone book: you want "Joe's Bookstore," you look it up, and the directory tells you it sits at 123 Main Street. DNS does the same thing for hosts, mapping a fully qualified domain name (FQDN) to an address. Two lookups matter:

  • Forward lookup — name to IP (an A record for IPv4, AAAA for IPv6).
  • Reverse lookup — IP to name (a PTR record, stored in a special in-addr.arpa zone).

Running your own internal DNS gives you fast, private name resolution for a LAN, a lab, or a server fleet without leaking internal hostnames to the public internet.

The solution: BIND and the named daemon

BIND ships in every major Linux distribution. The core pieces you will touch are:

  • /etc/named.conf — the main configuration file: global options, logging, and a zone stanza per domain.
  • Zone files in /var/named/ — the actual records (SOA, NS, A, PTR) for each zone.
  • rndc — the remote name daemon control utility for reloading and managing named.
  • named-checkconf and named-checkzone — validators that catch syntax errors before they take the server down.

The example below uses the domain example.lan and a server at 192.168.10.2. Substitute your own domain and addressing throughout.

Test scenario

ItemValue
Operating systemRHEL 9 / Rocky 9 / AlmaLinux 9 (works on 8 too)
Server IP192.168.10.2 / 24
Server hostnamens1.example.lan
Domain (forward zone)example.lan
Reverse zone10.168.192.in-addr.arpa
Client hostclient.example.lan = 192.168.10.10

Step 1: Install BIND

On modern Red Hat-family systems use dnf (older releases used yum; the syntax is identical):

  1. Install the server and its utilities:
    sudo dnf install -y bind bind-utils
  2. Confirm the package and binary version:
    named -v

On Debian or Ubuntu the package is named differently: sudo apt install -y bind9 bind9-utils dnsutils, the config lives under /etc/bind/, and the service is named (aliased as bind9). The concepts that follow are the same; only the paths change.

Step 2: Configure /etc/named.conf

Edit the main configuration file:

sudo vim /etc/named.conf

In the options block, tell named which addresses to listen on and which clients may query it. The stock file listens only on 127.0.0.1, which means nothing on your LAN can reach it — widen it:

options {
    listen-on port 53 { 127.0.0.1; 192.168.10.2; };
    listen-on-v6 port 53 { ::1; };
    directory "/var/named";
    dump-file "/var/named/data/cache_dump.db";
    statistics-file "/var/named/data/named_stats.txt";
    allow-query { localhost; 192.168.10.0/24; };
    allow-transfer { none; };
    recursion yes;
    dnssec-validation auto;
};

A few notes on these directives:

  • allow-query restricts who may ask questions. Limit it to your LAN subnet so the server is not an open resolver exposed to the internet.
  • recursion yes lets the server resolve names it is not authoritative for (good for an internal resolver). If this box should only answer for its own zones, set recursion no to avoid being abused in amplification attacks.
  • allow-transfer should be none unless you run a secondary (slave) server, in which case list only that secondary's IP.
  • dnssec-validation auto is the modern, correct setting. The old dnssec-enable and dnssec-lookaside options were removed in BIND 9.16+ and will cause named to refuse to start if you copy them from an old tutorial.

Set up forwarders (optional but recommended)

A forwarder tells your server to hand off any query it cannot answer locally to an upstream resolver instead of walking the root servers itself. This speeds up resolution and works well behind firewalls. Add this inside the options block:

    forwarders { 1.1.1.1; 8.8.8.8; };
    forward only;

forward only means "never try to resolve directly, always use the forwarders"; forward first tries the forwarders and falls back to recursion. With recursion yes and a cache, your server now doubles as a fast caching resolver for the LAN.

Declare the zones

At the end of /etc/named.conf (or in the included /etc/named.rfc1912.zones file), add one stanza for the forward zone and one for the reverse zone:

zone "example.lan" IN {
    type master;
    file "example.lan.forward";
    allow-update { none; };
};

zone "10.168.192.in-addr.arpa" IN {
    type master;
    file "example.lan.reverse";
    allow-update { none; };
};

Note the reverse zone name: the network 192.168.10.0/24 becomes 10.168.192.in-addr.arpa — the first three octets reversed, with .in-addr.arpa appended. This trips up many beginners, so write it out carefully.

Before going further, validate the configuration syntax:

sudo named-checkconf

No output means the file is syntactically valid. Fix any reported errors before continuing.

Step 3: Build the forward zone file

Create /var/named/example.lan.forward. This file maps names to addresses:

$TTL 1D
@    IN SOA  ns1.example.lan. admin.example.lan. (
              2026062801 ; serial
              1D         ; refresh
              1H         ; retry
              1W         ; expire
              3H )     ; minimum
@    IN NS   ns1.example.lan.
ns1  IN A    192.168.10.2
client IN A    192.168.10.10

Reading the records:

  • $TTL sets the default time-to-live (how long resolvers may cache answers).
  • SOA (Start of Authority) names the primary server and the admin contact. The contact admin.example.lan. is an email address with the @ replaced by a dot — it means admin@example.lan. The trailing dots make these names fully qualified; omitting a trailing dot causes BIND to append the zone name, a classic source of mangled records.
  • The serial uses the YYYYMMDDnn convention. You must increase this number every time you edit the file, or secondaries (and your own reloads) will ignore the changes.
  • NS declares the authoritative name server for the zone.
  • A records map a hostname to an IPv4 address. Use AAAA for IPv6.

Step 4: Build the reverse zone file

Create /var/named/example.lan.reverse. This file maps addresses back to names using PTR records:

$TTL 1D
@    IN SOA  ns1.example.lan. admin.example.lan. (
              2026062801 ; serial
              1D         ; refresh
              1H         ; retry
              1W         ; expire
              3H )     ; minimum
@   IN NS   ns1.example.lan.
2   IN PTR  ns1.example.lan.
10  IN PTR  client.example.lan.

The number on the left of each PTR line is the final octet of the host's address. Because the zone is 10.168.192.in-addr.arpa, the bare 2 expands to 2.10.168.192.in-addr.arpa, which is 192.168.10.2. The right-hand name must end in a trailing dot so it is treated as fully qualified. Every host you give an A record in the forward zone should normally get a matching PTR here.

Step 5: Permissions, SELinux, and validation

BIND runs as the unprivileged named user, so it must be able to read its zone files. Set the group and tighten the mode:

  1. Set ownership so named can read the files:
    sudo chown root:named /var/named/example.lan.forward /var/named/example.lan.reverse
  2. Restrict the mode:
    sudo chmod 640 /var/named/example.lan.forward /var/named/example.lan.reverse
  3. Restore SELinux context (essential on RHEL-family systems, or named is denied access):
    sudo restorecon -Rv /var/named
  4. Validate each zone file — this catches missing dots, bad serials, and typos before a restart:
    sudo named-checkzone example.lan /var/named/example.lan.forward
    sudo named-checkzone 10.168.192.in-addr.arpa /var/named/example.lan.reverse

A healthy zone prints OK and the loaded serial. If SELinux is in enforcing mode and you skip restorecon, named will fail to load the zones with permission-denied errors even though the file modes look correct — check with sudo ausearch -m avc -ts recent if something refuses to load.

Step 6: Start, enable, and open the firewall

Modern Linux uses systemd to manage services and firewalld for the firewall. The old service named start and chkconfig named on commands are deprecated; use:

  1. Start the daemon now and enable it at boot:
    sudo systemctl enable --now named
  2. Confirm it is running:
    sudo systemctl status named
  3. Open DNS in the firewall (port 53, both TCP and UDP):
    sudo firewall-cmd --permanent --add-service=dns
    sudo firewall-cmd --reload

After editing a zone later, you do not need a full restart — bump the serial, then reload with rndc:

  • Reload everything: sudo rndc reload
  • Reload a single zone: sudo rndc reload example.lan
  • Flush the cache after a record change: sudo rndc flush

DNS listens on both UDP and TCP port 53 — UDP for ordinary queries and TCP for large responses and zone transfers — so make sure both are allowed (the dns service handles both).

Common pitfalls to avoid

  • Forgetting to bump the serial. If you edit a zone but leave the serial unchanged, named serves the old data and secondaries never sync. Increment it on every edit.
  • Missing trailing dots. A name without a trailing dot gets the zone name appended, turning ns1.example.lan into ns1.example.lan.example.lan. Always end FQDNs with a dot in zone files.
  • SELinux and permissions. Wrong ownership or a stale SELinux context silently blocks named from reading zone files. Run chown root:named and restorecon -Rv /var/named.
  • Glue records. When a zone's name servers live inside that same zone, the parent must publish A records (glue) for them, or resolvers cannot find the server that holds the zone. For internal labs this matters once you delegate subdomains.
  • Copying obsolete options. dnssec-enable, dnssec-lookaside, and bindkeys-file were removed in current BIND. Leaving them in named.conf stops the daemon from starting — named-checkconf will flag them.
  • Open resolver. Leaving allow-query { any; } with recursion enabled on a public-facing box turns your server into a tool for DNS amplification attacks. Scope queries to your LAN.

Verify your DNS server

Use dig (from bind-utils) to test against the server directly. The @192.168.10.2 argument forces the query to your new server:

  1. Forward lookup:
    dig @192.168.10.2 client.example.lan
    Look for status: NOERROR and an ANSWER SECTION showing client.example.lan. ... A 192.168.10.10.
  2. Reverse lookup:
    dig @192.168.10.2 -x 192.168.10.2
    The answer should be a PTR pointing to ns1.example.lan.
  3. Quick check with nslookup (also handy on Windows clients):
    nslookup client.example.lan 192.168.10.2
  4. Tail the log if a query fails:
    sudo journalctl -u named -f

The presence of the aa flag in dig output means the answer is authoritative — proof your server owns the zone.

Point a Linux client at your new server

A client decides which resolvers to use from /etc/resolv.conf. Each nameserver line lists one DNS server by IP address, tried in order. Use IP addresses, never names — the system cannot resolve a name until it already knows how to reach a resolver.

  1. Edit the file:
    sudo nano /etc/resolv.conf
  2. Add your server (and a public fallback):
    search example.lan
    nameserver 192.168.10.2
    nameserver 1.1.1.1
  3. Test resolution:
    ping -c 3 client.example.lan

On systems managed by NetworkManager or systemd-resolved, /etc/resolv.conf is regenerated automatically and your hand edits may be overwritten on reboot. Set the DNS server on the connection instead, for example:

sudo nmcli con mod "System eth0" ipv4.dns "192.168.10.2"
sudo nmcli con up "System eth0"

If you also run IPv6, add the server's IPv6 address as another nameserver line and test with ping6 instead of ping. You can discover whether an upstream resolver has an IPv6 address with host <name>, which reports any AAAA record alongside the A record.

Key Takeaways

  • Install BIND with dnf install bind bind-utils, then drive everything through /etc/named.conf and the zone files in /var/named/.
  • Every zone needs an SOA, at least one NS, plus A/PTR records — and you must increment the SOA serial on every edit.
  • Validate before you reload using named-checkconf and named-checkzone; they catch the errors that otherwise crash named.
  • Use modern tooling: systemctl enable --now named, firewall-cmd --add-service=dns, and rndc reload — and drop the removed dnssec-enable/dnssec-lookaside options.
  • Watch SELinux, file permissions, and trailing dots; these three issues account for most "my zone won't load" problems.

Frequently Asked Questions

What is the difference between a forward and a reverse zone?

A forward zone holds A/AAAA records that map names to IP addresses, so a query for client.example.lan returns an address. A reverse zone lives under in-addr.arpa and holds PTR records that map an IP address back to a name, which mail servers and logging tools rely on. You typically maintain both, with one matching the other.

Why won't named start after I edit named.conf?

The most common causes are a syntax error or an obsolete directive copied from an old guide (such as dnssec-enable or dnssec-lookaside, removed in BIND 9.16+). Run sudo named-checkconf to pinpoint the line, then check sudo journalctl -u named -f for the exact failure.

How do I apply zone changes without restarting the server?

Increment the SOA serial in the zone file, run named-checkzone to validate it, then run sudo rndc reload <zone>. The rndc utility reloads only what changed, with no downtime, and sudo rndc flush clears cached answers if needed.

Is my DNS server safe to expose to the internet?

Not by default. Keep allow-query scoped to your LAN and set recursion no (or restrict recursion) on any public-facing authoritative server, otherwise it can be abused in DNS amplification attacks. An internal resolver with recursion should never be reachable from the public internet.

Want more hands-on Linux and self-hosting walkthroughs? Subscribe to @explorenystream on YouTube.