2026年11月12日

2026年11月12日

DoQ and DoT on One Server: DNS over QUIC and DNS over TLS Setup

This article is a localized edition of the Japanese original. Read the Japanese original

DoT and DoQ both use port 853, but DoT runs over TCP and DoQ over UDP (QUIC), so you can offer both at the same time from the same server with the same certificate. This article is for people running their own encrypted DNS resolver on a VPS, and walks through a setup that accepts DoT and DoQ side by side, preparing the certificate and firewall, and verifying it from a client.

Why offer both DoT and DoQ

DoT (RFC 7858) carries DNS over TLS, and its strength is wide client support, starting with Android's "Private DNS." DoQ (RFC 9250) carries DNS over QUIC; it is less prone to TCP head-of-line blocking and resumes connections faster, but client support is still limited.

If you provide both, apps that support DoQ use DoQ and every other device uses DoT. Also, some networks block UDP 853, and in that case DoT on TCP 853 may still get through. Offering both is more resilient to differences in users' environments than committing to only one.

Whether a client "switches to DoT if DoQ fails" depends on the app, however. Do not assume it will switch automatically; it is safer to be able to give users both endpoints.

How the setup is organized

Here the work is split as follows:

  • Recursive resolution and caching: Unbound (listening on 127.0.0.1 port 5300, not exposed externally)
  • Encryption termination: dnsdist (accepting DoT on TCP 853 and DoQ on UDP 853)

Unbound itself can listen for DoT, and newer versions can also listen for DoQ. DoQ, however, requires a QUIC library (such as ngtcp2) to be enabled at build time, so it may not be available in distribution packages. dnsdist can terminate DoT, DoQ and DoH together, so putting it in front lets you manage certificates and connection limits in one place. dnsdist supports DoQ from the 1.9 series, again depending on build options (as of October 2026). You will check whether your installed package includes DoQ in the startup log described below.

Before you start, back up your existing DNS configuration files and, if possible, run through the setup once on a test VPS before applying it to production.

Step 1: Prepare a certificate

Both DoT and DoQ use TLS 1.3, so you need a certificate for the server name (for example dns.example.com). You can get one from Let's Encrypt, just as for a web server.

# Example when port 80 is free (if a web server is running, switch to --webroot or similar)
sudo certbot certonly --standalone -d dns.example.com

dnsdist often runs as a dedicated user, so a common pitfall is that it cannot read the private key under /etc/letsencrypt/live/ and fails to start. The easiest fixes are to make the key readable via group permissions, or to copy it into a directory for dnsdist with a deploy hook at renewal time.

# Example of /etc/letsencrypt/renewal-hooks/deploy/dnsdist.sh
#!/bin/sh
install -o root -g _dnsdist -m 0640 /etc/letsencrypt/live/dns.example.com/fullchain.pem /etc/dnsdist/fullchain.pem
install -o root -g _dnsdist -m 0640 /etc/letsencrypt/live/dns.example.com/privkey.pem  /etc/dnsdist/privkey.pem
systemctl restart dnsdist

The user dnsdist runs as (_dnsdist in the example above) differs by package, so check it with systemctl cat dnsdist or similar and match it.

Step 2: Make Unbound listen locally only

Do not expose Unbound externally; have it accept queries only from dnsdist.

# /etc/unbound/unbound.conf.d/local-backend.conf
server:
    interface: 127.0.0.1@5300
    access-control: 127.0.0.0/8 allow
    access-control: 0.0.0.0/0 refuse
    do-ip6: yes

Check the syntax with unbound-checkconf, then restart. Be careful: if you open an outward-facing interface here, you end up with a resolver anyone can use over plaintext DNS.

Step 3: Listen for DoT and DoQ with dnsdist

-- /etc/dnsdist/dnsdist.conf
-- Networks allowed to use the resolver (change to match your home, office, etc.)
setACL({'127.0.0.0/8', '192.0.2.0/24', '2001:db8::/32'})

-- Backend (Unbound)
newServer({address='127.0.0.1:5300', name='unbound'})

-- DoT: TCP 853
addTLSLocal('0.0.0.0:853', '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')
addTLSLocal('[::]:853',    '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')

-- DoQ: UDP 853
addDOQLocal('0.0.0.0:853', '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')
addDOQLocal('[::]:853',    '/etc/dnsdist/fullchain.pem', '/etc/dnsdist/privkey.pem')

The key line is setACL. By default dnsdist only accepts queries from private addresses and the like, so if you want to use it from a smartphone while you are out, you have to list the allowed ranges explicitly. Conversely, if you allow 0.0.0.0/0, you get a resolver anyone can use, encrypted or not, which invites abuse and load. For personal or company use, narrow the allowed ranges or combine them with rate limiting.

Check the configuration, then start the service.

sudo dnsdist --check-config
sudo systemctl restart dnsdist
sudo journalctl -u dnsdist -n 50

Look in the log for errors about the DoQ listener (such as a message that the build does not support DoQ). If ss -lntup | grep 853 shows port 853 open on both TCP and UDP, the listeners are working.

Step 4: Open the firewall

The most common oversight when running DoT and DoQ together is forgetting to open UDP 853. Environments that only ran DoT often allow nothing but TCP 853.

# ufw example
sudo ufw allow 853/tcp
sudo ufw allow 853/udp

If your VPS provider or cloud security group also filters traffic, allow UDP 853 there too.

Step 5: Verify from a client

kdig, which ships with Knot DNS, is handy because it can test both DoT and DoQ (DoQ from the 3.3 series onward).

# DoT (also validates the certificate host name)
kdig @dns.example.com +tls +tls-hostname=dns.example.com +tls-ca example.com A

# DoQ
kdig @dns.example.com +quic example.com A

BIND's dig also supports +tls from 9.18 onward, but note that it does not support DoQ.

When checking, look at these three points:

  • Whether the response shows status: NOERROR and the expected A record
  • Whether DoT reports any certificate validation errors (a missing intermediate certificate shows up here)
  • If only DoQ times out, whether UDP 853 is blocked somewhere

If only DoQ fails while DoT succeeds, the cause is the server-side build, the UDP firewall or the user's network. If running kdig @127.0.0.1 +quic on the server succeeds, the server configuration is correct and you can isolate the problem to the network path.

Operational notes

If the deploy hook restarts dnsdist when certificates renew, DoT and DoQ switch to the new certificate at the same time. Test the renewal beforehand with sudo certbot renew --dry-run for peace of mind.

Also, encrypted DNS makes query contents hard to see from the network path, but the resolver operator can still see the queries. If you provide it inside a company, decide how much to log and how long to keep it, and be ready to explain this to users.

As a way to tell clients about the endpoints automatically, you can advertise DoT and DoQ support with DDR (RFC 9462) or SVCB records, but support varies by OS and app. The most reliable way to start is to have users configure the endpoint host name manually.

Summary

  • DoT uses TCP 853 and DoQ uses UDP 853, so one server can offer both with the same certificate
  • Making Unbound a local-only backend and terminating DoT and DoQ in dnsdist keeps management in one place
  • dnsdist's ACL and allowing UDP 853 in the firewall are the typical stumbling points
  • Test both with kdig +tls and kdig +quic, and if only DoQ fails, test from inside the server to see whether it is a network path problem
  • Apply certificate renewals together with a deploy hook, and test them beforehand with certbot renew --dry-run

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲