FreeBSD.software
Home/Guides/BIND on FreeBSD: Authoritative DNS Server Review
review·2026-04-09·12 min read

BIND on FreeBSD: Authoritative DNS Server Review

Review of BIND 9 on FreeBSD: authoritative and recursive DNS setup, DNSSEC, zone management, views, response rate limiting, and comparison with Unbound and NSD.

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

sh
pkg 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:

sh
sysrc 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

sh
named -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:

sh
zone "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

sh
named-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:

sh
dig @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.

sh
options { 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:

sh
dnssec-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:

sh
dig @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

sh
dig @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.

sh
acl "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:

sh
options { 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 10 limits identical responses to the same /24 prefix to 10/sec
  • slip 2 sends a truncated response every 2nd dropped query, signaling legitimate clients to retry over TCP
  • window 15 is 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:

sh
rndc reload example.com

Or reload all zones:

sh
rndc 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:

sh
include "/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:

sh
nsupdate -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):

sh
logging { channel query_log { file "/var/log/named/query.log" versions 3 size 100m; severity info; print-time yes; }; category queries { query_log; }; };
sh
mkdir -p /var/log/named chown bind:bind /var/log/named

Statistics. Enable the statistics channel for monitoring:

sh
statistics-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:

sh
sysrc 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.

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.