Last updated: 2026-02-11
dnsdist DNS over TLS/HTTPS Configuration Guide
This guide provides recommended DNS over TLS (DoT) and DNS over HTTPS (DoH) settings for dnsdist. dnsdist is a DNS load balancer and proxy from the PowerDNS project that can serve as a DoT/DoH frontend for any DNS backend.
Prerequisites
- dnsdist 1.5 or later (for DoT with TLS 1.3 cipher control; 1.4 for basic DoT)
- dnsdist 1.5 or later (for DoH support; 1.6+ for
customResponseHeaders) - A valid TLS certificate and private key
- One or more backend DNS resolvers or authoritative servers
Installation note: dnsdist is not in the base repositories for RHEL/CentOS or SLES. Install from the PowerDNS repository. On Debian/Ubuntu, dnsdist is available in the standard repositories.
DNS over TLS (DoT)
Frontend Listener
Configure dnsdist to accept DNS over TLS connections on port 853:
addTLSLocal('0.0.0.0:853', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', {
minTLSVersion='tls1.2',
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',
ciphersTLS13='TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
})
IPv6 Support
Add a second listener for IPv6:
addTLSLocal('[::]:853', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', {
minTLSVersion='tls1.2'
})
DNS over HTTPS (DoH)
Frontend Listener
Configure dnsdist to accept DNS over HTTPS connections on port 443:
addDOHLocal('0.0.0.0:443', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', '/dns-query', {
minTLSVersion='tls1.2',
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',
ciphersTLS13='TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
})
The /dns-query path is the standard DoH endpoint defined in RFC 8484.
Custom HTTP Headers
Add security headers to DoH responses (requires dnsdist 1.6+):
addDOHLocal('0.0.0.0:443', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', '/dns-query', {
minTLSVersion='tls1.2',
customResponseHeaders={['Strict-Transport-Security']='max-age=63072000', ['X-Content-Type-Options']='nosniff'}
})
Backend Servers
Plain DNS Backends
Forward queries to backend resolvers over plain DNS:
newServer({address='127.0.0.1:53', name='local-resolver'})
newServer({address='10.0.0.1:53', name='resolver-1'})
newServer({address='10.0.0.2:53', name='resolver-2'})
DNS over TLS Backends
Forward queries to upstream resolvers over TLS:
newServer({address='9.9.9.9:853', tls='openssl', subjectName='dns.quad9.net', name='quad9'})
newServer({address='1.1.1.1:853', tls='openssl', subjectName='cloudflare-dns.com', name='cloudflare'})
Version note: The
tlsandsubjectNameoptions fornewServer()require dnsdist 1.7+. On dnsdist 1.4-1.6 (Debian 11 ships 1.6.x), outgoing DoT to backends is not supported — backends must use plain DNS.
The subjectName option verifies the upstream server's certificate hostname.
TLS Session Tickets and Resumption
Configure TLS session tickets for improved performance:
addTLSLocal('0.0.0.0:853', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', {
minTLSVersion='tls1.2',
numberOfTicketsKeys=3,
ticketKeyFile='/etc/dnsdist/ssl/ticket.key',
sessionTimeout=86400
})
Generate a ticket key:
dd if=/dev/urandom bs=80 count=1 of=/etc/dnsdist/ssl/ticket.key 2>/dev/null
chmod 600 /etc/dnsdist/ssl/ticket.key
OCSP Stapling
Enable OCSP stapling for DoT and DoH listeners:
addTLSLocal('0.0.0.0:853', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', {
minTLSVersion='tls1.2',
ocspResponses={'/etc/dnsdist/ssl/ocsp.der'}
})
Fetch the OCSP response:
openssl ocsp -issuer /etc/dnsdist/ssl/chain.pem \
-cert /etc/dnsdist/ssl/fullchain.pem \
-url http://ocsp.example.com \
-respout /etc/dnsdist/ssl/ocsp.der
Access Control
Restrict access to the DNS service:
setACL({'127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '::1/128', 'fe80::/10'})
Load Balancing
Configure load balancing across backend servers:
setServerPolicy(leastOutstanding)
Available policies: firstAvailable, roundrobin, leastOutstanding, wrandom, whashed.
Complete Configuration
-- /etc/dnsdist/dnsdist.conf
-- Plain DNS listener (optional, for local clients)
addLocal('127.0.0.1:53')
-- DNS over TLS listener
addTLSLocal('0.0.0.0:853', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', {
minTLSVersion='tls1.2',
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',
ciphersTLS13='TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
})
-- DNS over HTTPS listener
addDOHLocal('0.0.0.0:443', '/etc/dnsdist/ssl/fullchain.pem', '/etc/dnsdist/ssl/privkey.pem', '/dns-query', {
minTLSVersion='tls1.2',
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',
ciphersTLS13='TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256',
customResponseHeaders={['Strict-Transport-Security']='max-age=63072000'}
})
-- Access control
setACL({'0.0.0.0/0', '::/0'})
-- Backend resolvers
newServer({address='127.0.0.1:5300', name='local-unbound'})
-- Load balancing
setServerPolicy(leastOutstanding)
-- Security
setMaxTCPClientThreads(64)
setMaxTCPQueuedConnections(1000)
-- Web interface (optional, bind to localhost only)
-- webserver('127.0.0.1:8083', 'password', 'apikey')
Verification
Test DNS over TLS:
kdig @dot.example.com +tls example.com A
Or with OpenSSL:
echo -ne '\x00\x1c\xab\xcd\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\x01\x00\x01' | \
openssl s_client -connect dot.example.com:853 -quiet 2>/dev/null | xxd
Test DNS over HTTPS:
curl -s -H 'Accept: application/dns-json' 'https://doh.example.com/dns-query?name=example.com&type=A'
Check TLS certificate and protocol:
echo | openssl s_client -connect dot.example.com:853 2>/dev/null | grep -E 'Protocol|Cipher'
Check dnsdist statistics:
dnsdist -e 'showServers()'
dnsdist -e 'showTLSContexts()'