BIND on FreeBSD: Authoritative DNS Server Review
BIND (Berkeley Internet Name Domain) is the most widely deployed DNS server software in the world. It has been the reference implementation of the DNS protocol since the 1980s, and BIND 9 -- the current major version -- is maintained by the Internet Systems Consortium (ISC). BIND can function as an authoritative nameserver, a recursive resolver, or both simultaneously. This flexibility is its core strength and its primary operational risk, since combining roles on a single instance creates a larger attack surface and more complex configuration.
On FreeBSD, BIND has deep roots. FreeBSD included BIND in the base system for decades before switching to Unbound for recursive resolution in FreeBSD 10.0. BIND remains available as a well-maintained package for authoritative DNS duties, split-horizon configurations, DNSSEC signing, and environments that need features beyond what Unbound and NSD provide.
This review covers BIND 9 installation on FreeBSD, authoritative and recursive configuration, DNSSEC, zone management, views for split-horizon DNS, response rate limiting, and how BIND compares with Unbound and NSD.
BIND 9 Capabilities
BIND 9 is a full-featured DNS server that supports:
- Authoritative serving: hosting zone data for domains you own
- Recursive resolution: resolving queries on behalf of clients by querying the DNS hierarchy
- DNSSEC signing: signing zones with cryptographic keys and serving signed responses
- DNSSEC validation: validating signatures on responses from other servers
- Views: serving different zone data to different clients based on source IP, TSIG key, or other criteria
- Dynamic updates: accepting zone changes via DNS UPDATE protocol (RFC 2136)
- Zone transfers: AXFR and IXFR for primary/secondary replication
- Response Rate Limiting (RRL): mitigating DNS amplification attacks
- Catalog zones: automating zone provisioning across primary and secondary servers
- TSIG authentication: securing zone transfers and dynamic updates with shared secrets
- DNS over TLS (DoT) and DNS over HTTPS (DoH): encrypted transport for client queries
Installation on FreeBSD
Binary Package
shpkg install bind918
This installs BIND 9.18.x (the current stable LTS branch). The binary is /usr/local/sbin/named, and the default configuration directory is /usr/local/etc/namedb/.
Enable BIND:
shsysrc named_enable="YES"
Directory Structure
shell/usr/local/etc/namedb/ named.conf # Main configuration master/ # Zone files for zones you are primary for slave/ # Cached zone files from zone transfers dynamic/ # Zones that accept dynamic updates keys/ # TSIG and DNSSEC keys working/ # Runtime data (managed-keys, journal files)
Verify Installation
shnamed -V
This displays the version, build options, default paths, and supported features. Confirm that DNSSEC, DoT, and DoH support are included.
Authoritative DNS Configuration
The primary use case for BIND on FreeBSD is serving authoritative DNS for domains you own.
Primary Zone Configuration
sh# /usr/local/etc/namedb/named.conf options { directory "/usr/local/etc/namedb/working"; pid-file "/var/run/named/pid"; listen-on { any; }; listen-on-v6 { any; }; # Disable recursion for an authoritative-only server recursion no; allow-query { any; }; # Rate limiting to mitigate amplification attacks rate-limit { responses-per-second 10; window 5; }; # Hide version string version "not disclosed"; }; zone "example.com" { type primary; file "/usr/local/etc/namedb/master/example.com.zone"; allow-transfer { 10.0.0.2; 10.0.0.3; }; # Secondary servers also-notify { 10.0.0.2; 10.0.0.3; }; }; zone "0.168.192.in-addr.arpa" { type primary; file "/usr/local/etc/namedb/master/192.168.0.rev"; allow-transfer { 10.0.0.2; 10.0.0.3; }; };
Zone File
sh# /usr/local/etc/namedb/master/example.com.zone $TTL 86400 @ IN SOA ns1.example.com. admin.example.com. ( 2026040901 ; Serial (YYYYMMDDNN format) 3600 ; Refresh (1 hour) 900 ; Retry (15 minutes) 1209600 ; Expire (2 weeks) 3600 ; Minimum TTL (1 hour, negative cache) ) ; Nameservers IN NS ns1.example.com. IN NS ns2.example.com. ; Mail IN MX 10 mail.example.com. ; A records IN A 203.0.113.10 ns1 IN A 203.0.113.11 ns2 IN A 203.0.113.12 mail IN A 203.0.113.13 www IN A 203.0.113.10 api IN A 203.0.113.20 ; AAAA records IN AAAA 2001:db8::10 www IN AAAA 2001:db8::10 ; CNAME records ftp IN CNAME www.example.com. cdn IN CNAME d123456.cloudfront.net. ; TXT records (SPF, DKIM, DMARC) IN TXT "v=spf1 mx a:mail.example.com -all" _dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com" mail._domainkey IN TXT "v=DKIM1; k=rsa; p=YOUR_DKIM_PUBLIC_KEY" ; CAA record (authorize Let's Encrypt only) IN CAA 0 issue "letsencrypt.org"
Secondary (Replica) Configuration
On the secondary server:
shzone "example.com" { type secondary; file "/usr/local/etc/namedb/slave/example.com.zone"; masters { 203.0.113.11; }; };
BIND automatically performs zone transfers when the primary's serial number increases.
Validate and Start
shnamed-checkconf /usr/local/etc/namedb/named.conf named-checkzone example.com /usr/local/etc/namedb/master/example.com.zone service named start
Test with dig:
shdig @localhost example.com A dig @localhost example.com MX dig @localhost example.com NS
Recursive DNS Configuration
While Unbound is the recommended recursive resolver for FreeBSD (it ships in the base system), BIND can serve as a recursive resolver when you need features like views or when combining authoritative and recursive roles.
shoptions { recursion yes; allow-recursion { 10.0.0.0/8; 192.168.0.0/16; 127.0.0.0/8; }; forwarders { }; # Empty = full recursion from root hints dnssec-validation auto; };
The allow-recursion ACL is critical. Never allow open recursion -- an open recursive resolver is a weapon for DNS amplification attacks.
For a dedicated recursive resolver on FreeBSD, Unbound is the better choice. See the Unbound DNS guide.
DNSSEC
DNSSEC adds cryptographic signatures to DNS responses, allowing resolvers to verify that responses have not been tampered with. BIND 9 supports both DNSSEC signing (authoritative) and DNSSEC validation (recursive).
Automated DNSSEC Signing
BIND 9.16+ supports fully automated DNSSEC key management with dnssec-policy:
shdnssec-policy "standard" { keys { ksk key-directory lifetime unlimited algorithm ecdsap256sha256; zsk key-directory lifetime 30d algorithm ecdsap256sha256; }; nsec3param iterations 0 optout no salt-length 0; }; zone "example.com" { type primary; file "/usr/local/etc/namedb/master/example.com.zone"; dnssec-policy "standard"; inline-signing yes; key-directory "/usr/local/etc/namedb/keys"; };
This tells BIND to:
- Generate KSK (Key Signing Key) and ZSK (Zone Signing Key) automatically
- Use ECDSA P-256 (fast, small signatures)
- Rotate ZSKs every 30 days automatically
- Use NSEC3 for authenticated denial of existence (hides zone contents from enumeration)
- Sign the zone inline without modifying the original zone file
After starting BIND, retrieve the DS record for your registrar:
shdig @localhost example.com DNSKEY | dnssec-dsfromkey -f - example.com
Submit the DS record to your domain registrar to complete the chain of trust.
Verify DNSSEC
shdig @localhost example.com A +dnssec
Look for the ad (Authenticated Data) flag in the response and RRSIG records accompanying the answer.
sh# External verification dig @8.8.8.8 example.com A +dnssec +cd delv @8.8.8.8 example.com A
Views (Split-Horizon DNS)
Views allow BIND to serve different responses to different clients. The most common use case is split-horizon DNS, where internal clients see private IP addresses and external clients see public addresses.
shacl "internal" { 10.0.0.0/8; 192.168.0.0/16; 127.0.0.0/8; }; view "internal" { match-clients { "internal"; }; recursion yes; allow-recursion { "internal"; }; zone "example.com" { type primary; file "/usr/local/etc/namedb/master/example.com.internal.zone"; }; }; view "external" { match-clients { any; }; recursion no; zone "example.com" { type primary; file "/usr/local/etc/namedb/master/example.com.external.zone"; }; };
The internal zone file contains private addresses:
sh# example.com.internal.zone www IN A 10.0.0.50 db IN A 10.0.0.60
The external zone file contains public addresses:
sh# example.com.external.zone www IN A 203.0.113.10 ; db record intentionally absent - not exposed externally
Views must be ordered from most specific to least specific. BIND evaluates them top to bottom and uses the first match.
Response Rate Limiting (RRL)
RRL mitigates DNS amplification attacks by limiting the rate of identical responses:
shoptions { rate-limit { responses-per-second 10; referrals-per-second 5; nodata-per-second 5; nxdomains-per-second 5; errors-per-second 5; all-per-second 100; window 15; slip 2; ipv4-prefix-length 24; ipv6-prefix-length 56; }; };
responses-per-second 10limits identical responses to the same /24 prefix to 10/secslip 2sends a truncated response every 2nd dropped query, signaling legitimate clients to retry over TCPwindow 15is the time window in seconds for rate calculations
RRL is essential for any authoritative server exposed to the internet. Without it, your server can be used as an amplifier in DDoS attacks.
Zone Management
Serial Number Strategy
Use the date-based format YYYYMMDDNN (year, month, day, revision number). Increment the serial for every change. BIND requires the serial to increase for secondary servers to detect changes.
sh# Increment serial automatically (use with caution) SERIAL=$(date +%Y%m%d)01
Reload Zones Without Restart
After editing a zone file and incrementing the serial:
shrndc reload example.com
Or reload all zones:
shrndc reload
Dynamic DNS Updates
Allow specific clients to update records dynamically:
sh# Generate a TSIG key tsig-keygen -a hmac-sha256 update-key > /usr/local/etc/namedb/keys/update-key.conf
Include the key and allow updates:
shinclude "/usr/local/etc/namedb/keys/update-key.conf"; zone "dynamic.example.com" { type primary; file "/usr/local/etc/namedb/dynamic/dynamic.example.com.zone"; allow-update { key "update-key"; }; journal "/usr/local/etc/namedb/dynamic/dynamic.example.com.zone.jnl"; };
Send an update:
shnsupdate -k /usr/local/etc/namedb/keys/update-key.conf << 'EOF' server 127.0.0.1 zone dynamic.example.com update add test.dynamic.example.com 300 A 10.0.0.99 send EOF
BIND vs Unbound
Unbound ships in the FreeBSD base system and is the recommended recursive resolver. BIND is better suited for authoritative DNS.
Recursive resolution. Unbound is purpose-built for recursive resolution. It is faster, uses less memory, has a smaller attack surface, and is easier to configure for this role. BIND can do recursion, but it is not as efficient or as secure in this role as Unbound.
Authoritative DNS. BIND is the more capable authoritative server. It supports dynamic updates, catalog zones, views, complex ACLs, and inline DNSSEC signing with automated key management. Unbound does not serve authoritative zones (it can serve local-zone data, but this is not the same as a full authoritative server).
Combined roles. BIND can serve as both authoritative and recursive on the same instance using views. Unbound cannot. If you need both roles on a single IP address, BIND is the only option among these two. However, splitting roles across separate instances (Unbound for recursion, BIND or NSD for authoritative) is the recommended architecture.
Security. Unbound has a significantly smaller codebase and attack surface. BIND has a longer history of security vulnerabilities, though BIND 9 has been substantially rewritten and ISC responds quickly to security issues.
Recommendation. Use Unbound for recursive resolution on FreeBSD (it is already in the base system). Use BIND for authoritative DNS when you need DNSSEC signing, views, dynamic updates, or zone transfers. Run them as separate processes on separate IP addresses or ports if you need both.
For the Unbound setup guide, see Unbound DNS on FreeBSD.
BIND vs NSD
NSD (Name Server Daemon) is an authoritative-only DNS server from NLnet Labs (the same organization behind Unbound). It is designed solely for serving authoritative zone data.
Authoritative performance. NSD is faster than BIND for serving static zones. It compiles zone data into an optimized binary format and serves responses with minimal processing. For high-traffic authoritative servers serving static zones, NSD has a measurable performance advantage.
Features. BIND has far more features: views, dynamic updates, inline DNSSEC signing, catalog zones, response policies (RPZ), and recursive resolution. NSD supports zone transfers and TSIG authentication, but lacks views, dynamic updates, and built-in DNSSEC signing (you sign zones offline with tools like ldns-signzone).
Configuration. NSD's configuration is simpler because it does less. A basic NSD configuration is 10-15 lines. A basic BIND configuration is 20-30 lines.
Recommendation. Use NSD if you serve static authoritative zones, want maximum query performance, and handle DNSSEC signing externally. Use BIND if you need dynamic updates, views, inline DNSSEC signing, or any of BIND's advanced features.
Performance on FreeBSD
BIND 9 on FreeBSD, serving authoritative zones from a 4-core server:
- Query rate (authoritative, cached): 100,000-200,000 queries/sec for simple A record lookups
- Query rate (DNSSEC-signed zones): 50,000-80,000 queries/sec (ECDSA P-256 signatures)
- Zone transfer speed: a 100,000-record zone transfers in under 2 seconds on a local network
- Memory usage: 50-100 MB for a server with a few dozen zones. Large deployments (10,000+ zones) can use several GB.
- Startup time: a few seconds for small configurations, up to a minute for servers with thousands of zones and DNSSEC signing
Kernel tuning for high-query-rate authoritative servers:
sh# /etc/sysctl.conf net.inet.udp.recvspace=262144 net.inet.udp.maxdgram=65536 kern.ipc.somaxconn=4096 kern.ipc.maxsockbuf=8388608
Operational Tips
Logging. Configure query logging for debugging (disable in production -- it generates enormous log volume):
shlogging { channel query_log { file "/var/log/named/query.log" versions 3 size 100m; severity info; print-time yes; }; category queries { query_log; }; };
shmkdir -p /var/log/named chown bind:bind /var/log/named
Statistics. Enable the statistics channel for monitoring:
shstatistics-channels { inet 127.0.0.1 port 8053 allow { 127.0.0.1; }; };
Access XML statistics at http://127.0.0.1:8053/ or JSON at http://127.0.0.1:8053/json. Feed this to Prometheus via the bind_exporter.
Running in a jail. BIND runs well in a FreeBSD jail. This provides network isolation and limits the impact of potential vulnerabilities:
sh# Create a jail for BIND jail -c name=dns ip4.addr=10.0.0.53 path=/jails/dns mount.devfs # Install and configure BIND inside the jail
Chroot. BIND can also run in a chroot (without a full jail) for lighter isolation:
shsysrc named_chrootdir="/var/named"
FAQ
Q: Should I use BIND or Unbound on FreeBSD?
A: It depends on the role. Use Unbound for recursive DNS resolution (it ships in the base system and is purpose-built for this). Use BIND for authoritative DNS serving, especially if you need DNSSEC signing, views, or dynamic updates.
Q: Can BIND run inside a FreeBSD jail?
A: Yes. BIND runs well in jails with no special configuration. This is the recommended deployment for authoritative servers exposed to the internet.
Q: How do I automate DNSSEC key rotation with BIND?
A: Use dnssec-policy in BIND 9.16+. It handles key generation, rollover, and retirement automatically. No manual key management or cron jobs needed.
Q: What happens if I forget to increment the zone serial?
A: Secondary servers will not detect the change and will continue serving the old zone data. Always increment the serial after any zone edit. Use rndc reload to apply changes on the primary.
Q: Can BIND serve DNS over HTTPS (DoH)?
A: Yes, BIND 9.18+ supports DoH natively. Configure it with the http and tls statements in the listen-on directive. For most deployments, it is simpler to terminate DoH at a reverse proxy (NGINX, HAProxy) and forward plain DNS to BIND.
Q: How do I monitor BIND with Prometheus?
A: Enable the statistics channel on port 8053, then use bind_exporter to convert BIND's XML/JSON statistics to Prometheus metrics. Scrape the exporter with Prometheus and visualize in Grafana.
Q: How many zones can BIND handle on FreeBSD?
A: BIND can handle tens of thousands of zones on a single FreeBSD server. ISPs and hosting providers commonly run BIND with 50,000+ zones. Memory is the main constraint -- allocate approximately 1-2 MB per zone for signed zones.
Q: Should I allow zone transfers (AXFR)?
A: Only to your secondary nameservers. Restrict transfers with allow-transfer per zone. Open zone transfers expose your entire zone data, which aids attackers in reconnaissance.