Last updated: 2026-02-13
Knot Resolver DNS over TLS/HTTPS Configuration Guide
This guide provides recommended DNS over TLS (DoT) and DNS over HTTPS (DoH) settings for Knot Resolver (kresd). Knot Resolver is a modern, caching recursive DNS resolver with built-in support for encrypted DNS protocols and DNSSEC validation.
Prerequisites
- Knot Resolver 5.5 or later
- GnuTLS 3.6 or later
- SSL certificates (for serving DoT/DoH to clients)
RHEL/CentOS: Install with
dnf install knot-resolver.Debian/Ubuntu: Install with
apt install knot-resolver.
Certificate Setup
Place your certificates in a dedicated directory:
mkdir -p /etc/knot-resolver/ssl
chmod 750 /etc/knot-resolver/ssl
chown knot-resolver:knot-resolver /etc/knot-resolver/ssl
cp server.crt /etc/knot-resolver/ssl/server-cert.pem
cp server.key /etc/knot-resolver/ssl/server-key.pem
chmod 640 /etc/knot-resolver/ssl/*.pem
chown knot-resolver:knot-resolver /etc/knot-resolver/ssl/*.pem
Serving DNS over TLS (DoT)
Configure Knot Resolver to accept DoT connections from clients on port 853.
Add to kresd.conf (or the configuration file at /etc/knot-resolver/kresd.conf):
-- Listen on standard DNS port
net.listen('0.0.0.0', 53, { kind = 'dns' })
net.listen('::', 53, { kind = 'dns' })
-- Listen on DNS over TLS port
net.listen('0.0.0.0', 853, { kind = 'tls' })
net.listen('::', 853, { kind = 'tls' })
-- TLS certificate and key
net.tls('/etc/knot-resolver/ssl/server-cert.pem', '/etc/knot-resolver/ssl/server-key.pem')
Serving DNS over HTTPS (DoH)
Configure Knot Resolver to accept DoH connections:
-- Listen on DNS over HTTPS port
net.listen('0.0.0.0', 443, { kind = 'doh2' })
net.listen('::', 443, { kind = 'doh2' })
-- Uses the same TLS certificates configured with net.tls()
Note:
doh2uses HTTP/2 for DNS over HTTPS. Knot Resolver handles TLS termination natively.
TLS Configuration
Protocol Versions and Cipher Suites
Knot Resolver uses GnuTLS. Configure TLS settings using GnuTLS priority strings:
net.tls_priority('NORMAL:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS1.0:-VERS-DTLS1.2:%SERVER_PRECEDENCE')
For a more restrictive configuration with only strong ciphers:
net.tls_priority('SECURE256:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS1.0:-VERS-DTLS1.2:+AES-256-GCM:+AES-128-GCM:+CHACHA20-POLY1305:%SERVER_PRECEDENCE')
Configuration Explained
- NORMAL / SECURE256 -- GnuTLS preset cipher suites.
SECURE256only allows 256-bit or higher security level ciphers. - -VERS-TLS1.0 / -VERS-TLS1.1 -- Disables TLS 1.0 and 1.1, allowing only TLS 1.2 and TLS 1.3.
- %SERVER_PRECEDENCE -- The server's cipher preference order takes priority over the client's.
Forwarding over TLS (Upstream DoT)
Configure Knot Resolver to forward queries to upstream resolvers over TLS using the policy module:
-- Load the policy module
modules.load('policy')
-- Forward all queries upstream over TLS
policy.add(policy.all(policy.TLS_FORWARD({
{'1.1.1.1', hostname='cloudflare-dns.com'},
{'1.0.0.1', hostname='cloudflare-dns.com'},
{'8.8.8.8', hostname='dns.google'},
{'8.8.4.4', hostname='dns.google'},
})))
The hostname parameter enables certificate verification against the upstream server's TLS certificate.
TLS Client Authentication (Upstream)
When forwarding to an upstream resolver that requires client certificates:
net.tls_client('/etc/knot-resolver/ssl/client-cert.pem', '/etc/knot-resolver/ssl/client-key.pem')
DNSSEC Validation
Knot Resolver validates DNSSEC by default. Ensure it remains enabled:
-- DNSSEC trust anchors (auto-managed)
trust_anchors.add_file('/var/lib/knot-resolver/root.keys', true)
Complete Configuration
-- Network listeners
net.listen('0.0.0.0', 53, { kind = 'dns' })
net.listen('::', 53, { kind = 'dns' })
net.listen('0.0.0.0', 853, { kind = 'tls' })
net.listen('::', 853, { kind = 'tls' })
net.listen('0.0.0.0', 443, { kind = 'doh2' })
net.listen('::', 443, { kind = 'doh2' })
-- TLS certificate
net.tls('/etc/knot-resolver/ssl/server-cert.pem', '/etc/knot-resolver/ssl/server-key.pem')
-- TLS protocol settings (GnuTLS priority string)
net.tls_priority('NORMAL:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-DTLS1.0:-VERS-DTLS1.2:%SERVER_PRECEDENCE')
-- Modules
modules.load('policy')
-- Forward all queries upstream over TLS
policy.add(policy.all(policy.TLS_FORWARD({
{'1.1.1.1', hostname='cloudflare-dns.com'},
{'1.0.0.1', hostname='cloudflare-dns.com'},
{'8.8.8.8', hostname='dns.google'},
{'8.8.4.4', hostname='dns.google'},
})))
-- DNSSEC trust anchors
trust_anchors.add_file('/var/lib/knot-resolver/root.keys', true)
-- Cache size (100 MB)
cache.size = 100 * MB
Client Configuration
systemd-resolved
Configure systemd-resolved to use your Knot Resolver over DoT:
[Resolve]
DNS=192.168.1.1
DNSOverTLS=yes
Browser DoH
Modern browsers can use DoH directly. Configure the custom DoH endpoint:
https://dns.example.com/dns-query
Verification
Check the configuration for errors:
kresctl validate
Test the DoT listener:
openssl s_client -connect dns.example.com:853
Test DNS resolution over TLS using kdig:
kdig @dns.example.com +tls example.com A
Test DNS resolution over HTTPS:
curl -s -H 'accept: application/dns-json' 'https://dns.example.com/dns-query?name=example.com&type=A'
Check Knot Resolver logs:
journalctl -u kresd@1 | grep -i tls