Last updated: 2026-06-25
PowerDNS DNSSEC & DNS over TLS Configuration Guide
This guide provides recommended DNSSEC and DNS over TLS (DoT) settings for PowerDNS Authoritative Server and PowerDNS Recursor. PowerDNS provides built-in DNSSEC support with straightforward key management through the pdnsutil command-line tool. For DoT, dnsdist (covered in a separate guide) serves as the TLS frontend for the Authoritative Server, while the Recursor supports outgoing DoT natively.
Prerequisites
- PowerDNS Authoritative Server 4.9 or later (earlier 4.x releases are end-of-life; 5.x is current)
- PowerDNS Recursor 5.x recommended (outgoing DoT was introduced in 4.6, but the 4.x line is end-of-life)
- A backend that supports DNSSEC (e.g.,
gmysql,gpgsql,lmdb,bind) - A valid TLS certificate and private key (for DoT via dnsdist)
Authoritative Server DNSSEC
Securing a Zone
Enable DNSSEC for an existing zone with a single command:
pdnsutil secure-zone example.com
This generates a KSK and ZSK using the default algorithm (ECDSAP256SHA256) and activates them immediately.
Algorithm Selection
Specify the algorithm when securing a zone:
pdnsutil secure-zone example.com ecdsap256sha256
| Algorithm | Recommendation |
|---|---|
rsasha256 |
Acceptable (2048-bit minimum) |
rsasha512 |
Acceptable |
ecdsap256sha256 |
Recommended |
ecdsap384sha384 |
Acceptable |
ed25519 |
Good (limited resolver support) |
Rectifying the Zone
After securing a zone, rectify it to generate NSEC/NSEC3 records and calculate ordername hashes:
pdnsutil rectify-zone example.com
Key Management
List all keys for a zone:
pdnsutil show-zone example.com
Add a new key:
# Add a new ZSK
pdnsutil add-zone-key example.com zsk active ecdsap256sha256
# Add a new KSK
pdnsutil add-zone-key example.com ksk active ecdsap256sha256
Rotate a ZSK:
# Add a new ZSK (active)
pdnsutil add-zone-key example.com zsk active ecdsap256sha256
# Deactivate the old ZSK (by key ID)
pdnsutil deactivate-zone-key example.com OLD_KEY_ID
# After TTL expiry, remove the old key
pdnsutil remove-zone-key example.com OLD_KEY_ID
DS Record Publication
Extract the DS record for publication at the parent zone:
pdnsutil show-zone example.com
This shows DS records in multiple digest formats. Publish the SHA-256 digest (type 2) with your registrar:
pdnsutil export-zone-ds example.com
You can also extract specific formats:
pdnsutil hash-zone-record example.com example.com
NSEC vs NSEC3
By default, PowerDNS uses NSEC. To switch to NSEC3 for authenticated denial of existence without zone enumeration:
pdnsutil set-nsec3 example.com '1 0 0 -'
pdnsutil rectify-zone example.com
The parameters '1 0 0 -' mean:
1- NSEC3 algorithm (SHA-1, the only defined algorithm)0- Flags (0 = no opt-out)0- Iterations (0 is recommended per RFC 9276)-- Empty salt (no salt, recommended per RFC 9276)
To revert to NSEC:
pdnsutil unset-nsec3 example.com
pdnsutil rectify-zone example.com
Authoritative Server Configuration
Enable DNSSEC in pdns.conf:
# /etc/pdns/pdns.conf
# Backend (example: PostgreSQL)
launch=gpgsql
gpgsql-host=127.0.0.1
gpgsql-dbname=pdns
gpgsql-user=pdns
gpgsql-password=secret
gpgsql-dnssec=yes
# Enable DNSSEC
# (Key storage is handled by the backend)
# Bind to all interfaces
local-address=0.0.0.0, ::
local-port=53
# Authoritative only (recursion is disabled by default in 4.5+)
# AXFR restrictions
disable-axfr=yes
allow-axfr-ips=192.0.2.1/32,198.51.100.1/32
# Logging
loglevel=4
log-dns-queries=no
Recursor DNSSEC Validation
PowerDNS Recursor validates DNSSEC-signed responses automatically when configured:
# /etc/pdns-recursor/recursor.conf
# Enable DNSSEC validation
dnssec=validate
# Log DNSSEC validation failures
dnssec-log-bogus=yes
# Local address
local-address=127.0.0.1, ::1
# Allow queries from local networks
allow-from=127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, ::1/128, fe80::/10
# Forward to authoritative servers (optional)
# forward-zones=example.com=192.0.2.1
# Root hints
hint-file=/usr/share/dns/root.hints # RHEL: /var/named/named.ca; or omit (built-in hints used by default)
DNSSEC validation modes:
| Mode | Description |
|---|---|
off |
No DNSSEC processing |
process-no-validate |
Set DO bit, pass records through, no validation |
process |
Set DO bit, set AD flag where applicable |
log-fail |
Validate, log failures, but serve bogus answers |
validate |
Full validation, return SERVFAIL for bogus answers |
Complete Configuration
Authoritative Server
# /etc/pdns/pdns.conf
# Backend
launch=gpgsql
gpgsql-host=127.0.0.1
gpgsql-dbname=pdns
gpgsql-user=pdns
gpgsql-password=secret
gpgsql-dnssec=yes
# Network
local-address=0.0.0.0, ::
local-port=53
# Security (recursion is disabled by default in 4.5+)
disable-axfr=yes
allow-axfr-ips=192.0.2.1/32,198.51.100.1/32
version-string=anonymous
# Performance
cache-ttl=60
negquery-cache-ttl=60
query-cache-ttl=20
# Logging
loglevel=4
log-dns-queries=no
After starting the server, secure your zones:
pdnsutil secure-zone example.com
pdnsutil set-nsec3 example.com '1 0 0 -'
pdnsutil rectify-zone example.com
pdnsutil export-zone-ds example.com
Validating Recursor
# /etc/pdns-recursor/recursor.conf
# Network
local-address=127.0.0.1, ::1
local-port=53
# Access control
allow-from=127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, ::1/128, fe80::/10
# DNSSEC
dnssec=validate
dnssec-log-bogus=yes
# Root hints
hint-file=/usr/share/dns/root.hints # RHEL: /var/named/named.ca; or omit (built-in hints used by default)
# Performance
threads=4
max-cache-entries=1000000
max-packetcache-entries=500000
# Security
version-string=anonymous
DNS over TLS (DoT)
Authoritative Server with dnsdist
PowerDNS Authoritative Server does not natively support DNS over TLS. Use dnsdist as a TLS-terminating frontend (see the dnsdist guide for full configuration):
-- /etc/dnsdist/dnsdist.conf
-- DNS over TLS frontend
addTLSLocal('0.0.0.0:853', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', {
minTLSVersion='tls1.2'
})
-- Forward to local PowerDNS Authoritative Server
newServer({address='127.0.0.1:53', name='pdns-auth'})
Recursor Outgoing DoT
PowerDNS Recursor 4.6+ supports forwarding queries to upstream resolvers over TLS. Specify the TLS port and server name for certificate verification:
# /etc/pdns-recursor/recursor.conf
# Forward to upstream over DoT
forward-zones-recurse=.=9.9.9.9:853#dns.quad9.net;149.112.112.112:853#dns.quad9.net
The #hostname suffix after the address enables TLS and verifies the server certificate against the specified hostname.
Version note: The
#hostnamesyntax for outgoing DoT requires PowerDNS Recursor 4.6+.
Recursor DoT Configuration
# /etc/pdns-recursor/recursor.conf
# Network
local-address=127.0.0.1, ::1
local-port=53
# Access control
allow-from=127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, ::1/128, fe80::/10
# DNSSEC
dnssec=validate
dnssec-log-bogus=yes
# Forward all queries over DoT
forward-zones-recurse=.=9.9.9.9:853#dns.quad9.net;149.112.112.112:853#dns.quad9.net;1.1.1.1:853#cloudflare-dns.com;1.0.0.1:853#cloudflare-dns.com
# Performance
threads=4
max-cache-entries=1000000
max-packetcache-entries=500000
# Security
version-string=anonymous
Security Notes
The cipher suite and protocol configuration in this guide addresses the following known TLS vulnerabilities:
- POODLE (CVE-2014-3566, 2014): SSL 3.0 is disabled. TLS_FALLBACK_SCSV was added in OpenSSL 1.0.1j / 1.0.2 (October 2014); SSL 3.0 disabled by default in OpenSSL 1.1.0 (August 2016).
- BEAST (CVE-2011-3389, 2011): Mitigated by recommending TLS 1.2 as the minimum; AEAD-only ciphers eliminate the CBC padding oracle.
- CRIME (CVE-2012-4929, 2012): TLS compression is off by default in OpenSSL 1.1.0+; do not enable it.
- Lucky13 (2013): AEAD-only cipher list eliminates CBC padding timing side-channels entirely.
- FREAK (CVE-2015-0204, 2015): EXPORT-grade ciphers are excluded. Removed from OpenSSL 1.1.0 (August 2016).
- LOGJAM (CVE-2015-4000, 2015): Short-key DHE is excluded; only ECDHE key exchange is recommended.
- Sweet32 (CVE-2016-2183, 2016): 3DES is excluded from the cipher string.
- ROBOT (2017): Static RSA key exchange is excluded; only ECDHE is recommended.
- Downgrade attacks: TLS_FALLBACK_SCSV prevents protocol version rollback.
The following are not addressable through TLS configuration alone:
- Heartbleed (CVE-2014-0160, 2014): A memory disclosure bug in OpenSSL 1.0.1 through 1.0.1f. Fixed in OpenSSL 1.0.1g (April 7, 2014). Addressed by patching OpenSSL, not by TLS configuration.
- BREACH (CVE-2013-3587, 2013): Not applicable. BREACH targets HTTP-level response compression; DNS-over-TLS does not involve HTTP. DNS-over-HTTPS uses HTTP but typically without compressible secret data.
- DROWN (CVE-2016-0800, 2016): Requires SSLv2 to be enabled on any server sharing the same private key. Ensure SSLv2 is disabled on all services that use the same certificate and key pair.
Verification
Check that a zone is properly signed:
pdnsutil check-zone example.com
Verify DNSSEC keys and DS records:
pdnsutil show-zone example.com
Test with dig:
dig @localhost example.com DNSKEY +dnssec +multiline
dig @localhost example.com A +dnssec
Verify the ad (Authenticated Data) flag is set when querying through the recursor:
dig @127.0.0.1 example.com A +dnssec
Check NSEC3 records:
dig @localhost example.com NSEC3PARAM
Use delv for detailed validation:
delv @localhost example.com A +rtrace
Test the full chain of trust from an external resolver:
dig example.com A +dnssec +trace
Verify the full DNSSEC chain of trust externally with the Mr.DNS DNSSEC Validation Check.