Encrypted queries go through the same path as UDP and TCP: local zones, views, blocklists, the
cache, conditional forwarding and the query log.
This page is about DNZ serving encrypted DNS to clients. To have DNZ forward over DoT,
DoH or DoQ to its upstreams, see Forwarding.
Turn it on
1
Get a certificate
The hostname (for example
dns.example.com) must be a public name, and the certificate must
come from a CA that devices trust, such as Let’s Encrypt. See
Get a certificate.2
Point DNZ at the certificate
/etc/dnz/dnz.env
[tls] section of the config file (cert, key, dot_addr,
https_addr, doq_addr, h3_addr). See Configuration.3
Open the ports
Ports 853 and 443 are below 1024. The systemd unit already has
CAP_NET_BIND_SERVICE. For Docker, publish the ports (TCP and UDP):docker-compose.yml
4
Restart DNZ
The log shows
dns-over-tls listening on …, dns-over-quic listening on …,
dns-over-http/3 listening on … and https listening on …. Settings → General → Encrypted
DNS shows which protocols are on.Renewing the certificate
DNZ checks the certificate files every minute and reads them again when they change, so renewing the certificate doesn’t need a restart. If the new files are broken, the old certificate stays in use and the error appears under Settings → General → Encrypted DNS.Ports for DoQ and DoH3
DoQ and DoH3 run over UDP on the same port numbers as DoT and HTTPS, so one certificate and one pair of port numbers cover everything. SetDNZ_DOQ_ADDR or DNZ_H3_ADDR to another address to
move them, or to off to turn them off. If their UDP port is taken (by another HTTP/3 server, say),
DNZ logs a warning and runs without them.
Over HTTP/3, DNZ answers only /dns-query. The UI stays on HTTPS over TCP, and DNZ doesn’t send
Alt-Svc, so browsers keep using HTTP/2. Clients reach DoH3 when they are configured for it, or by
finding it in an HTTPS/SVCB record, for example:
DoH behind your own reverse proxy
/dns-query is also served on the plain HTTP port (DNZ_HTTP_ADDR), so DoH can sit behind your own
HTTPS reverse proxy such as Caddy or nginx. Set DNZ_TRUSTED_PROXIES to the proxy’s address so the
real client IP is still used for views, blocklists and logs. See HTTPS.
Get a certificate
- DNZ serves the zone
- Zone on another provider
When DNZ is the public nameserver for the hostname’s zone, use DNZ’s own ACME endpoint with
lego. Create an API token with
lego stores
records.write for that zone, then:certificates/dns.example.com.crt and .key under --path. Point
DNZ_TLS_CERT and DNZ_TLS_KEY at those files. See ACME certificates.With the systemd unit (This can go in lego’s
DynamicUser), the service can’t read a root-owned key with mode 600.
Give it access through the ssl-cert group: turn on SupplementaryGroups=ssl-cert in the unit,
then after creating or renewing the certificate run:--renew-hook.Connect devices
Settings → General → Encrypted DNS shows the hostname, the DoH, DoQ and DoH3 addresses and the certificate’s expiry. Replacedns.example.com below with your hostname.
- Android
- iPhone, iPad, Mac
- Windows 11
- Browsers
- Linux
- AdGuard, dnsproxy
Android 9 and later: Settings → Network & internet → Private DNS → Private DNS provider
hostname →
dns.example.com.This uses DNS over TLS, so port 853 must be reachable.Troubleshooting
DoQ or DoH3 doesn't start
DoQ or DoH3 doesn't start
Their UDP port is probably taken by another program, such as another HTTP/3 server. DNZ logs a
warning and runs without them. Move them with
DNZ_DOQ_ADDR / DNZ_H3_ADDR, or turn them off
with off.A renewed certificate isn't used
A renewed certificate isn't used
Look under Settings → General → Encrypted DNS for the error. If the new files are broken,
DNZ keeps the old certificate. Under systemd, also check that the service can read the key (see
the
ssl-cert note above).Android says the Private DNS server can't be reached
Android says the Private DNS server can't be reached
Android uses DNS over TLS on port 853. Make sure the port is open in the firewall and published
in Docker, and that the hostname matches the certificate.