Setting up BIND9 for Internal DNS on RHEL9

Setting up BIND9 for Internal DNS on RHEL9 #

This guide covers setting up BIND9/named for internal reverse/forward DNS resolution on a RHEL9 server. Unlike public authoritative DNS servers, internal DNS servers provide recursive resolution for your internal network and handle local domain queries.

All IP addresses, network ranges, and hostnames in this guide are examples. Replace them with your actual values.

For the entirety of the guide we’ll be running every single command as root.

All the commands are intended only for RPM and dnf/yum based systems such as Red Hat, Fedora, CentOS etc.

Installation #

Installing BIND9 #

# Install BIND9 and utilities
dnf install bind bind-utils

# Start and enable the service
systemctl start named
systemctl enable named

# Check the service status
systemctl status named

Firewall Configuration #

Open the necessary ports for DNS services:

# Allow DNS traffic on both UDP and TCP
firewall-cmd --permanent --add-port=53/udp
firewall-cmd --permanent --add-port=53/tcp

# Reload firewall rules
firewall-cmd --reload

# Verify the configuration
firewall-cmd --list-all

Network Planning #

For this internal DNS setup, I’m using the following network configuration:

  • Internal network: 192.168.1.0/24
  • DNS servers:
    • Primary: 192.168.1.10 (dns01.domain.corp)
    • Secondary: 192.168.1.11 (dns02.domain.corp)
  • Internal domain: domain.corp

Main Configuration File #

The main BIND9 configuration file is /etc/named.conf. Here’s a complete internal DNS configuration:

//
// BIND9 Internal DNS Configuration
// Recursive DNS server for internal network
//

options {
    // Listen on specific interfaces
    listen-on port 53 { 127.0.0.1; 192.168.1.10; };

    // Directory for zone files
    directory "/var/named";

    // Log and statistics files
    dump-file "/var/named/data/cache_dump.db";
    statistics-file "/var/named/data/named_stats.txt";
    memstatistics-file "/var/named/data/named_mem_stats.txt";
    secroots-file "/var/named/data/named.secroots";
    recursing-file "/var/named/data/named.recursing";

    // Allow queries from anyone (adjust for your security needs)
    allow-query { any; };

    // Enable recursion for internal clients
    recursion yes;
    allow-recursion { 192.168.1.0/24; localhost; };

    // Security settings
    version "not currently available";
    allow-transfer { none; };

    // Disable DNSSEC validation for internal zones
    dnssec-validation no;

    // Enable query logging
    querylog yes;

    // Process and key file locations
    managed-keys-directory "/var/named/dynamic";
    pid-file "/run/named/named.pid";
    session-keyfile "/run/named/session.key";

    // Include system crypto policies
    include "/etc/crypto-policies/back-ends/bind.config";
};

// Logging configuration
logging {
    channel default_debug {
        file "data/named.run";
        severity dynamic;
    };

    channel zone_transfer_log {
        file "data/transfer.log" versions 10 size 50m;
        print-time yes;
        print-category yes;
        print-severity yes;
        severity info;
    };

    // Log zone transfers
    category notify { zone_transfer_log; };
    category xfer-in { zone_transfer_log; };
    category xfer-out { zone_transfer_log; };
};

// Root zone
zone "." IN {
    type hint;
    file "named.ca";
};

// Include default zones
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

// Forward zone for internal domain
zone "domain.corp" {
    type master;
    file "/var/named/domain.corp";
    allow-transfer { 192.168.1.11; };  // Allow secondary DNS
    allow-query { 192.168.1.0/24; 127.0.0.1; };
};

// Reverse zone for internal network
zone "1.168.192.in-addr.arpa" {
    type master;
    file "/var/named/1.168.192.in-addr.arpa";
    allow-transfer { 192.168.1.11; };  // Allow secondary DNS
    allow-query { 192.168.1.0/24; 127.0.0.1; };
};

Zone Files #

Forward Zone (domain.corp) #

Create /var/named/domain.corp:

$ORIGIN domain.corp.
$TTL 3600
@         IN  SOA  dns01.domain.corp.  admin.domain.corp. (
              2025070301  ; serial (YYYYMMDDNN format)
              21600       ; refresh after 6 hours
              3600        ; retry after 1 hour
              1209600     ; expire after 2 weeks
              86400 )     ; minimum TTL of 1 day

          IN  NS     dns01.domain.corp.
          IN  NS     dns02.domain.corp.

; Network infrastructure
gateway     IN  A   192.168.1.1      ; Gateway/Router
switch01    IN  A   192.168.1.2      ; Network Switch 1
switch02    IN  A   192.168.1.3      ; Network Switch 2
firewall    IN  A   192.168.1.4      ; Firewall

; DNS Servers
dns01       IN  A   192.168.1.10     ; Primary DNS
dns02       IN  A   192.168.1.11     ; Secondary DNS

; Domain Controllers
dc01        IN  A   192.168.1.20     ; Domain Controller 1
dc02        IN  A   192.168.1.21     ; Domain Controller 2

; Servers
fileserver  IN  A   192.168.1.30     ; File Server
mailserver  IN  A   192.168.1.31     ; Mail Server
webserver   IN  A   192.168.1.32     ; Web Server
dbserver    IN  A   192.168.1.33     ; Database Server
appserver   IN  A   192.168.1.34     ; Application Server
backupserver IN A   192.168.1.35     ; Backup Server
printserver IN  A   192.168.1.36     ; Print Server
monitoring  IN  A   192.168.1.37     ; Monitoring Server
proxy       IN  A   192.168.1.38     ; Proxy Server
jumphost    IN  A   192.168.1.39     ; Jump Host

; Workstations
ws001       IN  A   192.168.1.100    ; Workstation 001
ws002       IN  A   192.168.1.101    ; Workstation 002
ws003       IN  A   192.168.1.102    ; Workstation 003

; CNAME records for aliases
mail        IN  CNAME  mailserver.domain.corp.
web         IN  CNAME  webserver.domain.corp.
db          IN  CNAME  dbserver.domain.corp.
files       IN  CNAME  fileserver.domain.corp.
backup      IN  CNAME  backupserver.domain.corp.

Reverse Zone (1.168.192.in-addr.arpa) #

Create /var/named/1.168.192.in-addr.arpa:

$ORIGIN 1.168.192.in-addr.arpa.
$TTL 3600
@         IN  SOA  dns01.domain.corp.  admin.domain.corp. (
              2025070301  ; serial (YYYYMMDDNN format)
              21600       ; refresh after 6 hours
              3600        ; retry after 1 hour
              1209600     ; expire after 2 weeks
              86400 )     ; minimum TTL of 1 day

          IN  NS     dns01.domain.corp.
          IN  NS     dns02.domain.corp.

; PTR records for reverse lookups
; Network infrastructure
1         IN  PTR    gateway.domain.corp.
2         IN  PTR    switch01.domain.corp.
3         IN  PTR    switch02.domain.corp.
4         IN  PTR    firewall.domain.corp.

; DNS Servers
10        IN  PTR    dns01.domain.corp.
11        IN  PTR    dns02.domain.corp.

; Domain Controllers
20        IN  PTR    dc01.domain.corp.
21        IN  PTR    dc02.domain.corp.

; Servers
30        IN  PTR    fileserver.domain.corp.
31        IN  PTR    mailserver.domain.corp.
32        IN  PTR    webserver.domain.corp.
33        IN  PTR    dbserver.domain.corp.
34        IN  PTR    appserver.domain.corp.
35        IN  PTR    backupserver.domain.corp.
36        IN  PTR    printserver.domain.corp.
37        IN  PTR    monitoring.domain.corp.
38        IN  PTR    proxy.domain.corp.
39        IN  PTR    jumphost.domain.corp.

; Workstations
100       IN  PTR    ws001.domain.corp.
101       IN  PTR    ws002.domain.corp.
102       IN  PTR    ws003.domain.corp.

Configuration Validation #

Syntax Validation #

Always validate your configuration before restarting the service:

# Check named.conf syntax
named-checkconf /etc/named.conf

# Check individual zone files
named-checkzone domain.corp /var/named/domain.corp
named-checkzone 1.168.192.in-addr.arpa /var/named/1.168.192.in-addr.arpa

Restart Service #

# Restart BIND9
systemctl restart named

# Check service status
systemctl status named

# View recent logs
journalctl -u named -f

DNS Testing #

Test your DNS configuration:

# Test local resolution
dig @127.0.0.1 domain.corp NS
dig @127.0.0.1 dns01.domain.corp A

# Test reverse resolution
dig @127.0.0.1 -x 192.168.1.10

# Test specific records
dig @127.0.0.1 www.domain.corp A
dig @127.0.0.1 mail.domain.corp A

Secondary DNS Server Setup #

For redundancy, configure a secondary DNS server:

Note: Complete the installation and firewall configuration steps on the secondary server (192.168.1.11) before proceeding.

On Secondary Server #

# Add zone configurations to named.conf
zone "domain.corp" {
    type slave;
    file "/var/named/slaves/domain.corp";
    masters { 192.168.1.10; };
};

zone "1.168.192.in-addr.arpa" {
    type slave;
    file "/var/named/slaves/1.168.192.in-addr.arpa";
    masters { 192.168.1.10; };
};

Create Slaves Directory #

# Create directory for slave zone files
mkdir -p /var/named/slaves
chown named:named /var/named/slaves
chmod 755 /var/named/slaves

Client Configuration #

Configure your clients to use your DNS server:

Linux #

Edit /etc/resolv.conf:

nameserver 192.168.1.10
nameserver 192.168.1.11
search domain.corp

Troubleshooting Common Issues #

DNS Not Resolving #

# Check if BIND9 is running
systemctl status named

# Check listening ports
netstat -tulnp | grep :53

# Test local resolution
dig @127.0.0.1 domain.corp NS

# Check firewall
firewall-cmd --list-ports