Software & Configuration

BIND9 Authoritative DNS Server

Deploy and configure BIND9 authoritative DNS server with zones, records, DNSSEC, and zone transfers

What is BIND9?

BIND9 (Berkeley Internet Name Domain) is the most widely used open-source authoritative DNS server. It's production-ready, highly configurable, and supports advanced features like DNSSEC, zone transfers, and dynamic DNS updates. BIND9 is ideal for hosting multiple domains and managing DNS infrastructure at scale.

Installation on Ubuntu/Debian

sudo apt update
sudo apt install bind9 bind9utils bind9-doc dnsutils

Verify installation:

named -v
# BIND 9.18.x (Ubuntu)

Basic BIND9 Configuration

Main Configuration File

Edit /etc/bind/named.conf.options:

options {
    # Directory containing zone files
    directory "/var/lib/bind";

    # Listen on all interfaces (change if needed)
    listen-on { any; };
    listen-on-v6 { any; };

    # Allow DNS queries from anywhere (restrict if needed)
    allow-query { any; };

    # Disable recursive queries (authoritative only)
    recursion no;

    # Enable DNSSEC validation
    dnssec-validation auto;

    # Forwarders (optional, for fallback)
    # forwarders {
    #     8.8.8.8;
    #     8.8.4.4;
    # };

    # Transfer settings
    allow-transfer {
        192.168.1.101;  # Secondary nameserver IP
    };

    # Response policy zone (optional, for DNS filtering)
    # response-policy { zone "rpz.example.com"; };

    # Query logging (disable in production for performance)
    # querylog yes;

    # Rate limiting
    rate-limit {
        responses-per-second 10;
        window 1;
    };
};

# Logging configuration (optional)
logging {
    channel default_log {
        file "/var/log/bind/bind.log" versions 3 size 5m;
        severity dynamic;
        print-time yes;
    };
    category default { default_log; };
};

Zone Configuration

Edit /etc/bind/named.conf.local:

# Primary zone for example.com
zone "example.com" {
    type primary;
    file "/etc/bind/zones/db.example.com";
    allow-transfer { 192.168.1.101; };
};

# Reverse zone for PTR records (192.168.1.x)
zone "1.168.192.in-addr.arpa" {
    type primary;
    file "/etc/bind/zones/db.192.168.1";
};

# Secondary zone (slave) - read-only copy from primary
zone "example.org" {
    type secondary;
    primaries { 192.168.1.100; };
    file "/etc/bind/zones/db.example.org";
};

Create Zone Files

Forward Zone File

Create /etc/bind/zones/db.example.com:

; Zone file for example.com
$ORIGIN example.com.
$TTL 3600

; SOA (Start of Authority) record
@   IN  SOA ns1.example.com. admin.example.com. (
        2024032801  ; Serial (YYYYMMDDNN format)
        3600        ; Refresh (1 hour)
        1800        ; Retry (30 minutes)
        604800      ; Expire (7 days)
        86400       ; Minimum TTL (24 hours)
        )

; Nameserver records
@           IN  NS  ns1.example.com.
@           IN  NS  ns2.example.com.

; Nameserver A records
ns1         IN  A   192.168.1.100
ns2         IN  A   192.168.1.101

; MX records (mail servers)
@           IN  MX  10  mail.example.com.
@           IN  MX  20  mail2.example.com.

; A records
@           IN  A   203.0.113.10
www         IN  A   203.0.113.10
mail        IN  A   203.0.113.11
mail2       IN  A   203.0.113.12

; AAAA records (IPv6)
@           IN  AAAA 2001:db8::1
www         IN  AAAA 2001:db8::1

; CNAME records
blog        IN  CNAME www.example.com.
ftp         IN  CNAME www.example.com.

; TXT records
@           IN  TXT "v=spf1 mx -all"
_acme-challenge IN TXT "verification-code-here"

; SRV records (optional)
_sip._tcp   IN  SRV 10 60 5060 sipserver.example.com.

Set proper permissions:

sudo chown bind:bind /etc/bind/zones/db.example.com
sudo chmod 644 /etc/bind/zones/db.example.com

Reverse Zone File (PTR Records)

Create /etc/bind/zones/db.192.168.1:

; Reverse zone for 192.168.1.0/24
$ORIGIN 1.168.192.in-addr.arpa.
$TTL 3600

; SOA record
@           IN  SOA ns1.example.com. admin.example.com. (
        2024032801
        3600
        1800
        604800
        86400
        )

; Nameserver records
@           IN  NS  ns1.example.com.
@           IN  NS  ns2.example.com.

; PTR records
100         IN  PTR ns1.example.com.
101         IN  PTR ns2.example.com.
10          IN  PTR www.example.com.
11          IN  PTR mail.example.com.
12          IN  PTR mail2.example.com.

Validate Configuration

Check syntax before loading:

# Check main configuration
sudo named-checkconf /etc/bind/named.conf

# Check zone file syntax
sudo named-checkzone example.com /etc/bind/zones/db.example.com
# zone example.com/IN: loaded serial 2024032801
# OK

# Check reverse zone
sudo named-checkzone 1.168.192.in-addr.arpa /etc/bind/zones/db.192.168.1

Start and Reload BIND9

# Start the service
sudo systemctl start bind9
sudo systemctl enable bind9

# Check status
sudo systemctl status bind9

# Reload configuration (without restart)
sudo rndc reload

# Reload specific zone
sudo rndc reload example.com

# Reload all zones
sudo rndc reconfig

Query Your DNS Server

Test locally:

nslookup www.example.com localhost
dig @localhost www.example.com

# Query with verbose output
dig +trace @localhost www.example.com

# Query specific record type
dig @localhost example.com MX
dig @localhost example.com TXT

Test from remote:

dig @ns1.example.com www.example.com

Secondary (Slave) Zone Setup

On secondary nameserver, configure /etc/bind/named.conf.local:

zone "example.com" {
    type secondary;
    primaries { 192.168.1.100; };
    file "/var/lib/bind/zones/db.example.com";
};

The secondary server will automatically download the zone from primary via zone transfer (AXFR).

Verify zone transfer:

sudo systemctl restart bind9
ls -la /var/lib/bind/zones/

Allow Zone Transfers

In primary server's /etc/bind/named.conf.local, restrict transfers:

zone "example.com" {
    type primary;
    file "/etc/bind/zones/db.example.com";

    # Only allow transfers to secondary nameserver
    allow-transfer {
        192.168.1.101;     ; Secondary nameserver
        192.168.1.102;     ; Another secondary (if needed)
    };
};

Test zone transfer from secondary:

dig @ns1.example.com example.com AXFR

DNSSEC Basics

Generate DNSSEC Keys

cd /etc/bind/zones

# Generate KSK (Key Signing Key)
sudo dnssec-keygen -a ECDSAP256SHA256 -f KSK example.com

# Generate ZSK (Zone Signing Key)
sudo dnssec-keygen -a ECDSAP256SHA256 example.com

# Change ownership
sudo chown bind:bind K*

Sign the Zone

sudo dnssec-signzone -A -3 $(head -c 1000 /dev/urandom | md5sum | cut -b 1-16) \
    -N INCREMENT -o example.com -t -x example.com.key \
    db.example.com Kexample.com*.key

# This creates db.example.com.signed

Load Signed Zone

Edit /etc/bind/named.conf.local:

zone "example.com" {
    type primary;
    file "/etc/bind/zones/db.example.com.signed";
};

Reload BIND:

sudo rndc reload

Verify DNSSEC:

dig +dnssec www.example.com
# Should show RRSIG records

Firewall Configuration

Allow DNS queries through firewall:

# UFW
sudo ufw allow 53/tcp
sudo ufw allow 53/udp

# iptables
sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT

Restrict zone transfers to secondary nameserver only:

sudo iptables -A INPUT -p tcp --dport 53 -s 192.168.1.101 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 53 -j DROP

Monitoring and Logs

View BIND logs:

tail -f /var/log/syslog | grep named
# Or if using custom log file
tail -f /var/log/bind/bind.log

Monitor statistics:

rndc stats
# Writes to /var/log/bind/named.stats

Check zone transfers:

rndc zonestatus example.com

Dynamic DNS (DDNS)

Allow dynamic updates from specific IP:

zone "example.com" {
    type primary;
    file "/etc/bind/zones/db.example.com";

    allow-update { 203.0.113.50; };
};

Generate TSIG key for authentication:

tsig-keygen -a hmac-sha256 example.com.key

Alternatives to BIND9

For simpler setups, consider these alternatives:

  • PowerDNS: More modern, better performance, easier API integration
  • CoreDNS: Cloud-native, Kubernetes-friendly, plugin-based architecture
  • Knot DNS: High-performance, DNSSEC support, modern codebase
  • NSD: Lightweight authoritative-only server, suitable for small deployments

BIND9 remains the industry standard for flexibility and feature completeness.

Common Tasks

Add a New Subdomain

Edit zone file and increment SOA serial:

subdomain  IN  A   203.0.113.20
www.subdomain IN CNAME subdomain.example.com.

Reload zone:

sudo rndc reload example.com

Update Zone Serial

Increment serial in SOA record (use YYYYMMDDNN format):

; Before: 2024032801
; After:  2024032802

Reload and check propagation:

sudo rndc reload example.com
dig +short NS example.com @ns1.example.com

Delete a Record

Remove from zone file and reload:

sudo nano /etc/bind/zones/db.example.com
# Remove old record, increment serial
sudo rndc reload example.com

Troubleshooting

Zone won't load

Check syntax errors:

sudo named-checkzone example.com /etc/bind/zones/db.example.com
# Error output shows line numbers and issues

Secondary zone not transferring

Verify network connectivity:

telnet 192.168.1.100 53
dig @192.168.1.100 example.com AXFR

Check BIND logs for transfer errors:

tail -f /var/log/syslog | grep "example.com"

DNS queries slow or timing out

Check for query logging overhead:

sudo rndc querylog off
sudo rndc reload

Monitor BIND memory usage:

ps aux | grep named

Increase cache sizes in named.conf.options if needed.

On this page