Skip to main content

BIND Local DNS Resolver

BIND provides a local DNS resolver for SafeSquid, reducing lookup latency and improving cache hit rates for frequently accessed domains.

Why you need this: Relying on external DNS servers introduces latency, rate-limiting, and dependency on third parties. A local BIND resolver improves performance and reliability.

Prerequisites

Before You Start
  • Linux host with root/sudo access
  • SafeSquid installed
  • Firewall allows UDP/TCP port 53 outbound (to root DNS servers or forwarders)
  • NTP configured (for DNSSEC validation)

Installation and Configuration

1. Install BIND

Debian/Ubuntu:

sudo apt update
sudo apt install -y bind9 bind9-utils

RHEL/Rocky/CentOS:

sudo dnf install -y bind bind-utils

Verify installation:

named -v

Should print BIND version.


2. Configure BIND Options

Edit configuration file:

  • Debian/Ubuntu: /etc/bind/named.conf.options
  • RHEL/CentOS: /etc/named.conf
sudo nano /etc/bind/named.conf.options

Add/modify:

options {
directory "/var/cache/bind";

recursion yes;
allow-recursion { 127.0.0.1; 10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16; };

listen-on port 53 { 127.0.0.1; 10.0.0.1; }; // Replace 10.0.0.1 with your server IP
allow-query { any; };

dnssec-validation auto;
auth-nxdomain no;
minimal-responses yes;

rate-limit {
responses-per-second 25;
};
};

Explanation:

  • recursion yes — Enables BIND to query upstream DNS on behalf of clients
  • allow-recursion — Limits recursion to private IP ranges (prevents open resolver abuse)
  • listen-on — IP addresses BIND listens on (127.0.0.1 + server IP)
  • dnssec-validation auto — Validates DNSSEC signatures
  • rate-limit — Prevents DNS amplification attacks

Verify configuration syntax:

sudo named-checkconf

Should return nothing (silence means success).


3. Configure Root Hints and Local Zones (Optional)

Download root hints file:

sudo curl -o /var/cache/bind/root.hints https://www.internic.net/domain/named.root

Add root hints to configuration:

Edit /etc/bind/named.conf (or /etc/named.conf):

zone "." {
type hint;
file "/var/cache/bind/root.hints";
};

Configure local zone overrides (for internal domains):

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

sudo nano /etc/bind/named.conf.local

Add:

zone "corp.local" {
type forward;
forwarders { 10.0.0.10; 10.0.0.11; }; // Your internal DNS servers
};

Verify zone syntax:

sudo named-checkzone corp.local /dev/null

4. Enable and Start BIND

# Debian/Ubuntu:
sudo systemctl enable --now bind9
systemctl is-active bind9

# RHEL/CentOS:
sudo systemctl enable --now named
systemctl is-active named

Expected: Service shows active.


5. Point SafeSquid to Local Resolver

Edit /etc/resolv.conf on the SafeSquid server:

sudo nano /etc/resolv.conf

Set:

nameserver 127.0.0.1

Or if BIND is on a different server:

nameserver 10.0.0.1  # BIND server IP

Test DNS resolution:

dig @127.0.0.1 example.com

Expected: Answer section with IP address and low query time.


6. Harden Resolver (Production)

Enable logging:

Edit /etc/bind/named.conf (or /etc/named.conf):

logging {
channel default_log {
file "/var/log/named/default.log" versions 5 size 10m;
severity info;
print-time yes;
};
category resolver { default_log; };
category security { default_log; };
};

Create log directory:

sudo mkdir -p /var/log/named
sudo chown bind:bind /var/log/named

Restart BIND:

sudo systemctl restart bind9  # or named

Additional hardening:

  • Restrict recursion to SafeSquid server IP only (tighten allow-recursion)
  • Enable Response Policy Zones (RPZ) for threat blocking (optional)
  • Monitor logs for unusual query patterns

Verify BIND is Working

Test DNS Query

dig @127.0.0.1 example.com +stats

Expected output:

  • ANSWER SECTION with IP address
  • Query time in milliseconds
  • SERVER: 127.0.0.1#53 (confirming local resolver)

Check cache hit:

Run the same query twice:

dig @127.0.0.1 google.com
dig @127.0.0.1 google.com

Second query should be faster (cached response).


Check BIND Status

sudo rndc status

Expected: Shows version, uptime, and statistics.


Monitor Logs

# Debian/Ubuntu:
sudo journalctl -u bind9 -f

# RHEL/CentOS:
sudo journalctl -u named -f

# Or custom log:
sudo tail -f /var/log/named/default.log

Expected log entries:

[date] info: client 192.168.1.1#port: query: example.com IN A
[date] info: resolver: success for example.com

Troubleshooting

IssueLikely CauseFix
SERVFAIL on DNSSEC domainsNTP not configured or trust anchors missingConfigure NTP first, verify dnssec-validation auto
High query latencyNo caching or blocked egress to root serversCheck firewall allows UDP/TCP 53 outbound; verify root.hints
"Refused" queriesRecursion restricted or listen-on mismatchCheck allow-recursion includes client IP; verify listen-on has server IP
Port 53 already in useAnother resolver (systemd-resolved, dnsmasq) runningStop conflicting service: sudo systemctl disable --now systemd-resolved
Cache not workingBIND restarting frequently or low memoryCheck journalctl -u bind9 for errors; increase memory if needed

Still not working?

  1. Test DNS path:

    dig @8.8.8.8 example.com +short

    If this works but local doesn't, BIND config issue.

  2. Check BIND configuration:

    sudo named-checkconf
    sudo rndc status
  3. Trace DNS query:

    dig @127.0.0.1 example.com +trace

    Shows full resolution path from root to answer.

  4. Check logs:

    sudo journalctl -u bind9 -n 50

Next Steps

  1. Monit — Monitor BIND and auto-restart if it crashes
  2. NTP — Required for DNSSEC validation
  3. Integrated DNS Security — Configure DNSBL for malicious domain blocking
  4. Troubleshooting — DNS-specific troubleshooting

Related: Supporting Services Overview