Last updated: 2026-02-11
BIND DNSSEC & DNS over TLS Configuration Guide
This guide provides recommended DNSSEC and DNS over TLS (DoT) settings for BIND (Berkeley Internet Name Domain). DNSSEC adds cryptographic signatures to DNS records, allowing resolvers to verify that responses have not been tampered with. DNS over TLS encrypts DNS queries in transit. This guide covers authoritative zone signing, resolver-side validation, and DoT configuration.
Prerequisites
- BIND 9.16 or later (for
dnssec-policyinline signing support) - BIND 9.18 or later (for DNS over TLS support)
bind-dnssec-utilsor equivalent package fordnssec-keygen,dnssec-dsfromkey- A valid TLS certificate and private key (for DoT server mode)
- Access to the parent zone registrar to publish DS records
Version note: RHEL 8 ships BIND 9.11, which does not support
dnssec-policy(requires 9.16+). On BIND 9.11, use manual key generation withauto-dnssec maintain;anddnssec-enable yes;in the zone configuration instead. See the Manual Key Generation section below.Example zone configuration for BIND 9.11:
zone "example.com" { type primary; file "/var/named/example.com.zone"; auto-dnssec maintain; dnssec-enable yes; inline-signing yes; key-directory "/var/named/keys"; };Important:
dnssec-enablewas removed in BIND 9.18+ (Debian 12, Ubuntu 24.04). Do not use it on 9.18 or later — it will cause a startup failure. It is only needed on BIND 9.11-9.13.Path note: This guide uses RHEL/CentOS paths (
/etc/named.conf,/var/named/). On Debian/Ubuntu, use/etc/bind/named.conf,/var/cache/bind/for zone files, and/etc/bind/bind.keysinstead of/etc/named.root.key. On SLES, config is at/etc/named.confbut zone files are under/var/lib/named/.
DNSSEC Overview
DNSSEC uses a chain of trust from the DNS root to your zone:
- ZSK (Zone Signing Key) -- Signs individual DNS records in the zone
- KSK (Key Signing Key) -- Signs the DNSKEY RRset and is referenced by the parent zone's DS record
- DS Record -- Published in the parent zone, linking the parent's chain of trust to your KSK
- RRSIG -- Cryptographic signatures over each RRset
- NSEC/NSEC3 -- Authenticated denial of existence
Authoritative Server Configuration
Using dnssec-policy (Recommended)
BIND 9.16+ supports dnssec-policy for fully automated key generation, signing, and rollover:
dnssec-policy "standard" {
keys {
ksk key-directory lifetime unlimited algorithm ecdsap256sha256;
zsk key-directory lifetime P90D algorithm ecdsap256sha256;
};
dnskey-ttl 3600;
publish-safety PT1H;
retire-safety PT1H;
purge-keys P90D;
signatures-refresh P5D;
signatures-validity P14D;
signatures-validity-dnskey P14D;
max-zone-ttl 86400;
zone-propagation-delay PT5M;
parent-ds-ttl 3600;
parent-propagation-delay PT1H;
nsec3param iterations 0 optout no salt-length 0;
};
Apply the policy to a zone:
zone "example.com" {
type primary;
file "/var/named/example.com.zone";
dnssec-policy "standard";
inline-signing yes;
key-directory "/var/named/keys";
};
Algorithm Selection
Use ECDSAP256SHA256 (algorithm 13) for new deployments. It provides strong security with small key and signature sizes:
| Algorithm | ID | Recommendation |
|---|---|---|
| RSASHA256 | 8 | Acceptable (use 2048-bit minimum) |
| RSASHA512 | 10 | Acceptable |
| ECDSAP256SHA256 | 13 | Recommended |
| ECDSAP384SHA384 | 14 | Acceptable |
| ED25519 | 15 | Good (limited resolver support) |
Automatic Key Rollover
The dnssec-policy handles key rollover automatically based on the configured lifetimes. The ZSK lifetime of P90D (90 days) triggers automatic ZSK rollovers. The KSK lifetime of unlimited means KSK rollovers must be initiated manually.
Monitor key states:
rndc dnssec -status example.com # BIND 9.18+; on 9.16, use: rndc signing -list example.com
Manual Key Generation
If not using dnssec-policy, generate keys manually:
# Generate KSK
dnssec-keygen -a ECDSAP256SHA256 -f KSK example.com
# Generate ZSK
dnssec-keygen -a ECDSAP256SHA256 example.com
Include the keys in your zone file:
$INCLUDE Kexample.com.+013+12345.key
$INCLUDE Kexample.com.+013+67890.key
Sign the zone:
dnssec-signzone -A -3 $(head -c 16 /dev/urandom | od -A n -t x1 | tr -d ' \n') \
-N INCREMENT -o example.com -t example.com.zone
DS Record Publication
After signing your zone, extract the DS record and publish it at your registrar or parent zone:
dnssec-dsfromkey /var/named/keys/Kexample.com.+013+12345.key
This outputs DS records in multiple digest formats:
example.com. IN DS 12345 13 2 ABCDEF1234567890...
Publish the SHA-256 (digest type 2) DS record with your domain registrar.
Resolver Configuration (DNSSEC Validation)
Configure BIND as a validating resolver:
options {
directory "/var/named";
// Enable DNSSEC validation
dnssec-validation auto;
// Use the built-in root trust anchors
// (managed-keys-directory for RFC 5011 auto-updates)
managed-keys-directory "/var/named/dynamic";
bindkeys-file "/etc/named.root.key";
recursion yes;
allow-recursion { localnets; localhost; };
};
The dnssec-validation auto; setting uses the built-in root zone trust anchor and automatically validates DNSSEC-signed zones.
Trust Anchors
BIND ships with the root zone trust anchor. For custom trust anchors:
trust-anchors {
example.com. initial-key 257 3 13 "base64-encoded-key-data";
};
Complete Configuration
Authoritative Server
// /etc/named.conf
options {
directory "/var/named";
listen-on { any; };
listen-on-v6 { any; };
allow-transfer { none; };
allow-query { any; };
recursion no;
// Key directory for DNSSEC keys
key-directory "/var/named/keys";
};
// DNSSEC signing policy
dnssec-policy "standard" {
keys {
ksk key-directory lifetime unlimited algorithm ecdsap256sha256;
zsk key-directory lifetime P90D algorithm ecdsap256sha256;
};
dnskey-ttl 3600;
publish-safety PT1H;
retire-safety PT1H;
purge-keys P90D;
signatures-refresh P5D;
signatures-validity P14D;
signatures-validity-dnskey P14D;
max-zone-ttl 86400;
zone-propagation-delay PT5M;
parent-ds-ttl 3600;
parent-propagation-delay PT1H;
nsec3param iterations 0 optout no salt-length 0;
};
// Signed zone
zone "example.com" {
type primary;
file "/var/named/example.com.zone";
dnssec-policy "standard";
inline-signing yes;
key-directory "/var/named/keys";
};
Validating Resolver
// /etc/named.conf (resolver)
options {
directory "/var/named";
listen-on { 127.0.0.1; 10.0.0.1; };
recursion yes;
allow-recursion { localnets; localhost; };
dnssec-validation auto;
managed-keys-directory "/var/named/dynamic";
bindkeys-file "/etc/named.root.key";
// Rate limiting
rate-limit {
responses-per-second 10;
};
// Minimal responses
minimal-responses yes;
};
zone "." {
type hint;
file "named.ca";
};
DNS over TLS (DoT)
BIND 9.18 and later supports DNS over TLS for both serving encrypted queries and forwarding to upstream resolvers over TLS.
Version note: DoT support requires BIND 9.18+. The
tlsconfiguration block used below is not available in earlier versions. RHEL 9 and SLES 15 ship BIND 9.16, which does not support DoT natively. On those systems, consider using a TLS-terminating proxy such as stunnel or dnsdist for encrypted DNS transport.
TLS Profile
Define a TLS profile with your certificate and key:
tls local-tls {
cert-file "/etc/named/ssl/fullchain.pem";
key-file "/etc/named/ssl/privkey.pem";
protocols { TLSv1.2; TLSv1.3; };
ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305";
prefer-server-ciphers yes;
};
Listening for DoT
Accept DNS over TLS queries on port 853:
options {
listen-on port 853 tls local-tls { any; };
listen-on-v6 port 853 tls local-tls { any; };
};
Forwarding over TLS
Configure a TLS profile for upstream resolvers and forward queries over TLS:
tls upstream-tls {
ca-file "/etc/pki/tls/certs/ca-bundle.crt"; // Debian/Ubuntu: /etc/ssl/certs/ca-certificates.crt
remote-hostname "dns.quad9.net";
};
options {
forwarders port 853 tls upstream-tls {
9.9.9.9;
149.112.112.112;
};
forward only;
};
The remote-hostname option verifies the upstream server's TLS certificate hostname.
Complete DoT Server Configuration
// /etc/named.conf (DoT-enabled authoritative server)
tls local-tls {
cert-file "/etc/named/ssl/fullchain.pem";
key-file "/etc/named/ssl/privkey.pem";
protocols { TLSv1.2; TLSv1.3; };
prefer-server-ciphers yes;
};
options {
directory "/var/named";
// Plain DNS
listen-on { any; };
listen-on-v6 { any; };
// DNS over TLS
listen-on port 853 tls local-tls { any; };
listen-on-v6 port 853 tls local-tls { any; };
allow-transfer { none; };
allow-query { any; };
recursion no;
key-directory "/var/named/keys";
};
dnssec-policy "standard" {
keys {
ksk key-directory lifetime unlimited algorithm ecdsap256sha256;
zsk key-directory lifetime P90D algorithm ecdsap256sha256;
};
dnskey-ttl 3600;
signatures-refresh P5D;
signatures-validity P14D;
signatures-validity-dnskey P14D;
max-zone-ttl 86400;
nsec3param iterations 0 optout no salt-length 0;
};
zone "example.com" {
type primary;
file "/var/named/example.com.zone";
dnssec-policy "standard";
inline-signing yes;
key-directory "/var/named/keys";
};
DoT Verification
Test DNS over TLS with kdig:
kdig @ns.example.com +tls example.com A
Or with OpenSSL:
echo | openssl s_client -connect ns.example.com:853 2>/dev/null | grep -E 'Protocol|Cipher'
Firewall
Open port 853 for DNS over TLS:
firewall-cmd --permanent --add-port=853/tcp
firewall-cmd --reload
Verification
Check that a zone is signed:
dig @localhost example.com DNSKEY +dnssec +multiline
Verify RRSIG records exist:
dig @localhost example.com A +dnssec
Look for the ad (Authenticated Data) flag in responses:
dig @resolver example.com A +dnssec
Use delv for detailed DNSSEC validation:
delv @localhost example.com A +rtrace
Verify the DS record matches:
dig example.com DS +short
Check DNSSEC chain of trust:
drill -S example.com
Check the DNSSEC signing status in BIND:
rndc dnssec -status example.com # BIND 9.18+; on 9.16, use: rndc signing -list example.com
rndc zonestatus example.com