DNS over TLS
  • 20 Dec 2023
  • 3 Minutes to read
  • Contributors
  • Dark
  • PDF

DNS over TLS

  • Dark
  • PDF

Article Summary

NB: This document is retained for historical interest only as "named" and "dig" have supported TLS natively since BIND release 9.17.7.

RFC 7858 specifies DNS over TLS (Transport Layer Security). There are multiple ways to implement DoT. One implementation example, which uses nginx, is provided in the contrib directory of the BIND 9 distribution, entitled 'dnspriv'. This is documented at https://dnsprivacy.org/wiki/.

This article explains how to provide a DNS over TLS service using BIND 9 and stunnelThe setup of a privacy aggregator is at the end.

BIND 9 configuration: nothing special, but if you want to limit external insecure access to the service you can play with listen-on clause address and port, acl, or even a system firewall as BIND 9 provides no per-transport protocol access control.

stunnel setup for the opportunistic privacy profile:

  • Create a X.509 public key certificate, for instance by:
openssl genrsa -out dns.key 1024

openssl req -new -key dns.key -out dns.crt -x509

This creates a self-signed certificate, enough for clients performing no authentication.

  • Create a stunnel configuration dnstls.conf:

accept = 853

connect =

cert = dns.crt

key = dns.key

The service_name should be dns according to documentation. The DNS over TLS well-known port is 853; stunnel will accept any TLS connection on this port and forward content in TCP to (localhost) on port 53(dns).

  • Launch stunnel in daemon mode using the configuration file:
stunnel dnstls.conf

stunnel setup for the the out-of-band key-pinned privacy profile:

  • You should use a real X.509 CA but for experiments you can create a CA certificate by:
openssl genrsa -out ca.key 1024

openssl req -new -key ca.key -out ca.crt -x509 -extensions v3_ca
  • Create a X.509 public key certificate in a X.509 Certificate Authority, for instance the homemade CA:
openssl genrsa -out dns.key 1024

openssl req -new -key dns.key -out dns.req

openssl x509 -req -in dns.req -out dns.crt -CA ca.crt -CAkey ca.key -CAcreateserial
  • Add in stunnel configuration:
CAfile = ca.crt

This makes stunnel add the CA certificate to the chain during TLS handshake (as it is supposed to do).

  • Launch stunnel in daemon mode

How to test the service using getdns (https://getdnsapi.net).

  • Install (or configure and compile) getdns with the getdns_query tool you can find in src/test of the distribution.

  • If you'd like to authenticate the server, the CA must be known. The simplest way to do it is:

$ export SSL_CERT_FILE=.../ca.crt

% setenv SSL_CERT_FILE .../ca.crt

If you have a shell or a c-shell filling the ... by the path where the OpenSSL library can find the CA certificate.

openssl rsa -in dns.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

or from the certificate:

openssl x509 -in dns.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
  • A typical call could be:
getdns_query -s foo.example.org a @ -l L

-l L ask for TLS transport (vs. U for UDP or T for TCP)

  • or with key-pinning:
getdns_query -s foo.example.org a @ -l L -K 'pin-sha256="KAGwR1fXzY4JJtBP1yYoAisc+4yNomT6VrFPwkMi5qE="' -m

-K specifies a public key pin, -m requires authentication (vs -n for no authentication).

BIND 9 setup for a privacy aggregator uses, for instance:

options {


    forwarders { port 1053; };

    forward only;


server {

    tcp-only yes;



forwarders makes all queries to be forwarded to the designated service on another port, forward only disables fallback to standard resolution, and the tcp-only clause in the server entry enforces the use of TCP transport (note this feature was added in version 9.11).

stunnel setup for a privacy aggregator is in client mode with, for instance:


client = yes

accept = localhost:1053

connect = <server>:853

To test the privacy aggregator setup: <client_hosts> --- *:53 <named> localhost:1053 <stunnel> ---- *:853 <unbound> an unbound configuration could be:




    ssl-port: 853

    ssl-service-key: dns.key

    ssl-service-pen: dns.crt

    do-udp: no