What's Actually Happening
BIND DNS server fails to resolve domain names. Queries return SERVFAIL, NXDOMAIN, or timeout errors.
The Error You'll See
```bash $ dig @localhost example.com
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 12345 ```
Query refused:
status: REFUSEDNo answer:
```bash ;; QUESTION SECTION: ;example.com. IN A
;; AUTHORITY SECTION: . 3600 IN SOA a.root-servers.net. ```
Timeout:
;; connection timed out; no servers could be reachedWhy This Happens
- 1.Zone configuration errors - Syntax errors in zone files
- 2.Missing zones - Zone not configured or loaded
- 3.Forwarding issues - Upstream DNS not reachable
- 4.Permission errors - BIND cannot read zone files
- 5.DNSSEC issues - Signature validation failures
- 6.Recursion disabled - Server not allowing recursive queries
- 7.Firewall blocking - Port 53 not accessible
Step 1: Check BIND Status
```bash # Check BIND service: systemctl status named systemctl status bind9
# Check process: ps aux | grep named
# Check configuration: named-checkconf
# Check zone files: named-checkzone example.com /etc/bind/zones/example.com.zone
# Check logs: journalctl -u named -f tail -f /var/log/named.log
# Check listening ports: netstat -tlnp | grep named ss -tlnp | grep named
# DNS ports: # 53 - UDP and TCP # 953 - RNDC control
# Check version: named -v
# Test configuration: named -g -u bind # Runs in foreground with debug ```
Step 2: Check Zone Configuration
```bash # List configured zones: rndc zonestatus example.com
# Or from config: grep "zone" /etc/named.conf grep "zone" /etc/bind/named.conf.local
# Check zone file: cat /etc/bind/zones/example.com.zone
# Verify zone syntax: named-checkzone example.com /etc/bind/zones/example.com.zone
# Zone file example: $TTL 86400 @ IN SOA ns1.example.com. admin.example.com. ( 2024010101 ; Serial 3600 ; Refresh 1800 ; Retry 604800 ; Expire 86400 ) ; Minimum
@ IN NS ns1.example.com. @ IN A 192.168.1.10 ns1 IN A 192.168.1.1
# Check zone loaded: rndc status
# Reload zones: rndc reload systemctl reload named
# Check for zone errors: journalctl -u named | grep -i zone
# Zone configuration in named.conf: zone "example.com" { type master; file "/etc/bind/zones/example.com.zone"; allow-update { none; }; };
# Slave zone: zone "example.com" { type slave; file "/var/lib/bind/example.com.zone"; masters { 192.168.1.1; }; }; ```
Step 3: Fix Configuration Errors
```bash # Check main config: named-checkconf /etc/named.conf named-checkconf /etc/bind/named.conf
# Common errors:
# 1. Missing semicolons: # Wrong: allow-query { localhost } # Right: allow-query { localhost; };
# 2. Missing braces: options { recursion yes; };
# 3. Wrong file paths: file "/etc/bind/zones/example.com.zone"; # Check file exists: ls -la /etc/bind/zones/
# 4. Permission issues: ls -la /etc/bind/zones/example.com.zone chown bind:bind /etc/bind/zones/*.zone chmod 644 /etc/bind/zones/*.zone
# Check options: options { directory "/var/cache/bind"; recursion yes; allow-query { any; }; forwarders { 8.8.8.8; 8.8.4.4; }; dnssec-validation auto; };
# Check for include files: grep include /etc/named.conf
# Test after fix: named-checkconf && echo "Config OK" ```
Step 4: Check Recursion Settings
```bash # Check recursion enabled: grep recursion /etc/named.conf
# Enable recursion: options { recursion yes; allow-recursion { any; }; }
# Restrict recursion to specific networks: allow-recursion { 192.168.0.0/16; 10.0.0.0/8; };
# Check allow-query: allow-query { any; }; # Or restrict: allow-query { localhost; 192.168.0.0/16; };
# For authoritative only: recursion no;
# Test recursion: dig @localhost google.com
# Should return answer if recursion works
# Test with specific type: dig @localhost example.com A dig @localhost example.com MX
# Check cache: rndc dumpdb -cache # View: /var/named/data/cache_dump.db ```
Step 5: Fix Forwarding Issues
```bash # Check forwarders: grep forwarder /etc/named.conf
# Configure forwarders: options { forwarders { 8.8.8.8; 8.8.4.4; }; forward only; }
# Or forward first (try forwarders, then resolve directly): forward first;
# Test forwarder reachable: ping 8.8.8.8 nc -zuv 8.8.8.8 53
# Test forwarder works: dig @8.8.8.8 google.com
# Check forwarding logs: journalctl -u named | grep -i forward
# Conditional forwarding: zone "internal.example.com" { type forward; forwarders { 192.168.1.1; }; };
# Check forwarder statistics: rndc stats cat /var/named/data/named.stats ```
Step 6: Check DNSSEC Configuration
```bash # Check DNSSEC settings: grep dnssec /etc/named.conf
# DNSSEC validation: dnssec-validation auto;
# Disable DNSSEC validation (for testing): dnssec-validation no;
# Check for DNSSEC errors: journalctl -u named | grep -i dnssec
# DNSSEC keys: ls -la /etc/bind/keys/
# Signed zone file: # example.com.zone.signed
# Check DNSSEC chain: dig @localhost example.com DNSKEY dig @localhost example.com DS
# DNSSEC troubleshooting: # Check signature: dig @localhost example.com +dnssec
# Disable DNSSEC temporarily: rndc validation off
# Re-enable: rndc validation on
# Check for expired signatures: dnssec-signzone -A example.com.zone ```
Step 7: Check Firewall and Network
```bash # Check firewall for DNS: iptables -L -n | grep 53
# Allow DNS: iptables -I INPUT -p udp --dport 53 -j ACCEPT iptables -I INPUT -p tcp --dport 53 -j ACCEPT
# Using ufw: ufw allow 53/udp ufw allow 53/tcp
# Using firewalld: firewall-cmd --add-service=dns --permanent firewall-cmd --reload
# Test port: nc -zuv localhost 53
# Check if listening: ss -ulnp | grep :53
# Check from client: dig @server-ip example.com
# Check network: ping server-ip traceroute server-ip
# Check for NAT issues: # DNS over TCP sometimes blocked # Check with: dig @server-ip example.com +tcp ```
Step 8: Debug Resolution Issues
```bash # Enable debug logging: # In named.conf: logging { channel default_debug { file "data/named.run"; severity dynamic; }; };
# Or: logging { channel query.log { file "/var/log/query.log"; severity debug 3; }; category queries { query.log; }; };
# Reload: rndc reload
# Watch logs: tail -f /var/log/named.log
# Query with debug: dig @localhost example.com +trace
# Check response: dig @localhost example.com +stats
# Check authoritative servers: dig example.com NS +short
# Trace resolution: dig @localhost example.com +trace
# Check SERVFAIL reason: dig @localhost example.com +dnssec +cd # +cd disables DNSSEC check
# If +cd works, DNSSEC issue ```
Step 9: Fix Common Issues
```bash # Fix NXDOMAIN for existing domain: # Check zone serial: # Must increment serial after changes # Before: 2024010101 # After: 2024010102
# Fix SERVFAIL: # 1. Check zone syntax: named-checkzone example.com zonefile
# 2. Check DNSSEC # 3. Check file permissions # 4. Check logs
# Fix REFUSED: # Check allow-query: allow-query { any; };
# Fix timeout: # 1. Check firewall # 2. Check recursion enabled # 3. Check forwarders
# Clear cache: rndc flush
# Reload configuration: rndc reload
# Restart BIND: systemctl restart named
# Check for slave transfer issues: # On master: allow-transfer { slave-ip; };
# On slave: masters { master-ip; };
# Force zone transfer: rndc retransfer example.com
# Check transfer: dig @localhost example.com AXFR ```
Step 10: BIND Verification Script
```bash # Create verification script: cat << 'EOF' > /usr/local/bin/check-bind.sh #!/bin/bash
echo "=== BIND Service ===" systemctl status named 2>/dev/null || systemctl status bind9 2>/dev/null || echo "Service not running"
echo "" echo "=== Process ===" ps aux | grep named | grep -v grep || echo "No named process"
echo "" echo "=== Configuration Check ===" named-checkconf 2>&1 || echo "Configuration errors found"
echo "" echo "=== Listening Ports ===" netstat -tlnp 2>/dev/null | grep :53 || ss -tlnp | grep :53 || echo "Not listening on port 53"
echo "" echo "=== UDP Listening ===" ss -ulnp | grep :53 || netstat -ulnp | grep :53 || echo "Not listening on UDP 53"
echo "" echo "=== Zone Files ===" grep -h "file " /etc/named.conf /etc/bind/named.conf.local 2>/dev/null | head -10
echo "" echo "=== Zone Check ===" for zonefile in $(grep -h "file " /etc/named.conf /etc/bind/named.conf.local 2>/dev/null | grep -oE '"[^"]+"|'"'"'[^'"'"']+'"'"'' | tr -d "\"'" | head -5); do if [ -f "$zonefile" ]; then zonename=$(basename $zonefile .zone 2>/dev/null || echo "unknown") echo "Checking: $zonefile" named-checkzone $zonename $zonefile 2>&1 | head -3 fi done
echo "" echo "=== Recursion Setting ===" grep -E "^[\t ]*recursion" /etc/named.conf /etc/bind/named.conf.options 2>/dev/null | head -3
echo "" echo "=== Forwarders ===" grep -A 5 "forwarders" /etc/named.conf /etc/bind/named.conf.options 2>/dev/null | head -10
echo "" echo "=== Test Resolution ===" dig @localhost google.com +short 2>/dev/null | head -3 || echo "Resolution test failed"
echo "" echo "=== Test Local Zone ===" dig @localhost localhost +short 2>/dev/null || echo "Local resolution failed"
echo "" echo "=== Firewall ===" iptables -L -n 2>/dev/null | grep 53 || ufw status 2>/dev/null | grep 53 || echo "Check firewall manually"
echo "" echo "=== Recent Logs ===" journalctl -u named --no-pager -n 10 2>/dev/null || tail /var/log/named.log 2>/dev/null | tail -10 || echo "No logs"
echo "" echo "=== Recommendations ===" echo "1. Run named-checkconf to verify configuration" echo "2. Check zone files with named-checkzone" echo "3. Ensure recursion enabled for caching server" echo "4. Verify firewall allows port 53 UDP/TCP" echo "5. Check DNSSEC configuration if issues" echo "6. Increment serial after zone changes" echo "7. Check file permissions on zone files" EOF
chmod +x /usr/local/bin/check-bind.sh
# Usage: /usr/local/bin/check-bind.sh ```
BIND DNS Resolution Checklist
| Check | Expected |
|---|---|
| Service running | named process active |
| Port listening | UDP/TCP 53 accessible |
| Zone files | Syntax valid |
| Recursion | Enabled for caching |
| Forwarders | Reachable |
| DNSSEC | Valid or disabled |
| Firewall | Port 53 allowed |
Verify the Fix
```bash # After fixing BIND DNS resolution
# 1. Check config named-checkconf // No errors
# 2. Check zones named-checkzone example.com /etc/bind/zones/example.com.zone // Zone OK
# 3. Test local dig @localhost example.com // Returns A record
# 4. Test external dig @localhost google.com // Returns answer (recursion works)
# 5. Check logs journalctl -u named -f // No errors
# 6. Test from client dig @server-ip example.com // Resolution works ```
Related Issues
- [Fix DNS Server Not Responding](/articles/fix-dns-server-not-responding)
- [Fix DNS Propagation Issues](/articles/fix-dns-propagation-issues)
- [Fix PowerDNS Query Failed](/articles/fix-powerdns-query-failed)