3.9 KiB
Enable DoH and DoT
Besides plain DNS on port 53, nxdns can answer encrypted queries from your devices: DNS over HTTPS (DoH) on port 443 and DNS over TLS (DoT) on port 853. Both are off by default, and both need a certificate and its private key, as PEM files.
1. Get a certificate
Devices check the certificate against the name you give them, so use a certificate for a name you control, from an ACME client such as certbot, lego or Caddy. Android's Private DNS setting, for example, takes a hostname and needs a certificate a phone trusts.
To try it out first, a self-signed certificate is enough:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout /etc/nxdns/key.pem -out /etc/nxdns/cert.pem -days 365 \
-subj "/CN=nxdns.lan" \
-addext "subjectAltName=DNS:nxdns.lan,IP:192.168.1.10"
Replace nxdns.lan and 192.168.1.10 with the name and address your devices will use.
The key must be readable by the user nxdns runs as, and by nobody else. Under systemd that is the nxdns user:
chown nxdns:nxdns /etc/nxdns/cert.pem /etc/nxdns/key.pem
chmod 0644 /etc/nxdns/cert.pem
chmod 0600 /etc/nxdns/key.pem
Under Docker, put both files in etc-nxdns/ next to compose.yaml and give them to uid 65532 the same way, since the container cannot change the read-only mount itself.
2. Turn the listeners on
In file mode, add both sections to the configuration file:
.doh_server = .{
.enabled = true,
.cert_path = "/etc/nxdns/cert.pem",
.key_path = "/etc/nxdns/key.pem",
},
.dot_server = .{
.enabled = true,
.cert_path = "/etc/nxdns/cert.pem",
.key_path = "/etc/nxdns/key.pem",
},
In database mode, open System in the web interface, tick enabled under DoH Server and DoT Server, check the certificate and key paths, and save.
Both listeners bind every address on their standard ports by default; bind and port change that. The packaged systemd unit already allows binding ports below 1024. Under Docker, uncomment the 443 and 853 lines under ports: in compose.yaml.
3. Check and restart
In file mode, check loads the certificate and key the same way the listeners will:
nxdns check --config /etc/nxdns/config.zon
It fails when a file is unreadable or when the key does not belong to the certificate, and warns when the key is readable by others:
FAIL doh_server.key_path: '/etc/nxdns/other.pem': private key does not belong to the certificate
WARN dot_server.key_path: '/etc/nxdns/key.pem' is mode 644; a TLS key must be readable by its owner only
Then restart nxdns (systemctl restart nxdns, or docker compose restart). The log names both listeners:
info(nxdns): doh listener on 0.0.0.0:443
info(nxdns): dot listener on 0.0.0.0:853
If a certificate cannot be loaded, nxdns refuses to start and exits 2 rather than run without the listener you asked for:
doh_server: '/etc/nxdns/cert.pem' + '/etc/nxdns/key.pem': private key file is not readable
nxdns run failed: BadCertificate
4. Test them
DoT, with a dig from BIND 9.18 or newer:
dig @192.168.1.10 +tls example.com A +short
DoH, using curl's own DoH resolver to look up example.com:
curl -sS --doh-url https://nxdns.lan/dns-query -o /dev/null \
-w 'resolved to %{remote_ip}\n' https://example.com
Add --doh-insecure to the curl command while you test with a self-signed certificate. DoH is served at /dns-query only, over HTTP/1.1, as both GET and POST.
Renewing the certificate
nxdns checks both files every 30 seconds and switches to a renewed pair on its own; connections already open finish on the old one. There is nothing to restart. Each reload is logged:
info(cert_store): certificate reloaded from /etc/nxdns/cert.pem
To load it at once instead, press Reload certificates on the System page. If a reload fails, nxdns keeps serving the certificate it has and says why.