Secure DoT/DoH Private DNS


Private "DNS In A Box" - is a lightweight (ish) container designed for to provide secure, roaming DNS for use with piHole and Traefik.

The use-case is quite specific, but may be surprisingly useful for many. Read on.

This container makes use of:

  • the bitnami/minideb image

  • the totally wonderful dnsdist - which provides the DoH, DoT and DNS functionality

  • Some of the authors own scripting (bash and lua)

Table Of Contents

Why encrypt DNS?

Normal DNS queries are sent "plaintext" - meaning anyone or anything (person or code) with access to your traffic can see which sites your devices are requesting. This could happen between your device and your DNS server, or your DNS server and your ISP's server. Whilst a DNS request may not indicate a subsequent connection to a returned address, it's a fairly good bet that a request would probably be followed up by a connection to that address.

DNS-over-HTTPS (DoH) and DNS-over-TLS (DoT) and DNSCrypt have been created to allow encryption of DNS queries so that requests can be encrypted - so only your device(s) and your DNS server of choice know what you requested, until an actual connection is initiated. Traffic inspection can still show IP addresses, although with the declining IPv4 address space and prevalance of virtual hosting, IP addresses are not a guarantee of which sites may be connected to - but SNI can still reveal which site was requested.

DNS encryption combined with ESNI makes things a bit better, and diab is here to assist with the former....

The use case

As mentioned, this is quite specific - but is designed to keep as much of 'your' device traffic as secure as can be.

The assumption is that you already (or want to):

  • Run your own Linux server at home

  • Run Docker on said server

  • Have an internet connection with a unique (static or dynamic) external IP address

  • Have a home router with port forwarding capabilities

  • Run your own local DNS service/filtering (i.e. piHole) -- You don't want devices/browsers going to "other" DNS providers -- You may already have piHole (or other DNS tool) configured to securely talk to another DNS service, i.e. OpenDNS via DNSCrypt

  • Run your own VPN (i.e. WireGuard) to secure your mobile device traffic - and get piHole cover when roaming -- You want to use the "Always-On" and "Block connections without VPN" options on your mobile

  • Don't want to operate a "public" facing DNS service, that you need to connect to your VPN....

  • Don't want a mobile device to report "No internet connection" when using restricted DNS

If you want to setup your own Linux, OMV, Docker, Traefik and piHole box - read our article on how to do that!

If you want to setup WireGuard for the above setup - read our article on how to do that!

The browser and/or device dilemma

Firefox supports DoH, and (unless you switch it off) might start using it with DNS servers you can't control (i.e. bypassing your DNS). You can't block port 443 outbound, as you'd block all secure web traffic...it's a blessing and a curse.

Android supports DoT (which uses TCP port 853, thus can be blocked).

Chrome supports DoH (currently via the chrome://flags menu) but only if your specified DNS host offers it as well as normal DNS. We're assuming this means Chrome will do a reverse lookup on your DNS IP, and if it gets a name returned, it will try a DoH query to the HTTPS hostname.

Most DNS servers will be 'normal' unencrypted ones, and those (like piHole) don't offer DoT or DoH....

Make sense?

As an example, the author runs a Linux box running OpenMediaVault, running Docker. Docker is hosting:

  • a piHole container to provide DNS (with adblocking) to the LAN

  • a WireGuard container to provide a VPN "back to the LAN" when roaming away from home WiFi (also enabling piHole adblock coverage when roaming) -- piHole is configured to use a DNSCrypt (with DNSSEC) connection to an external filter (OpenDNS).

  • a Traefik container for a variety of things, but it handles dynamic SSL certificate provision

However, the author's ideal is to ensure Android's new "Always-On" and "Block connections without VPN" settings are "on" - and that "Private DNS" is always set to a trusted host (i.e. the author's own).

NOTE: Enabling "Block connections without VPN" means all traffic will go over WireGuard, which may not be ideal in all circumstances. If you disable (or don't enable) "Block connections without VPN" then you'll effectively get "split tunnelling" - access to your private LAN will go over WireGuard but "other" (i.e. internet) traffic will go as normal. If you enable "Private DNS" then regardless of the "Block connections without VPN" setting, your DNS traffic will always go to your server. You need to choose the level of security that is right for you.

Either way - you might at this point think "Hang on, won't WireGuard be encrypting the DNS traffic to piHole, and DNScrypt be encrypting all the outgoing queries? Why do you need Private DNS?!" - and you'd partially be right...however:

  1. WireGuard needs a hostname or IP to connect to. The author's IP is dynamic - so Dynamic DNS is in use to update a known hostname for WireGuard to connect to

  2. WireGuard needs access to DNS to lookup the hostname, which it must do before it can connect.

  3. The only way to set DNS in Android is either) -- in WiFi settings ('standard' DNS only, i.e. not encrypted) or -- use Private DNS

  4. "Private DNS" on Android has 3 options - "Off", "Automatic" or a user provided hostname can be forced -- If "Off" is set, plaintext DNS will be used -- If "Automatic" is used, Android will connect to a user provided hostname (if provided) or any it can 'find' (which may not be yours, i.e. Google or QuadDNS) - even if WireGuard later overrides it -- If you force a user provided hostname, Android will ONLY use secure DNS to lookup WireGuard

  5. Thus you need to provide a secure DNS server for your initial connection. You could use an external service, but skips piHole etc...and...

  6. You probably don't want any secure DNS server you provide to be publically available but....

  7. Your roaming (cellular) IP will change frequently - so you can't firewall it to check clients before WireGuard has connected

  8. Even once WireGuard connects, "Private DNS" will still be used - so it needs to be resolvable/accessible internally and externally

  9. piHole doesn't offer DoT, so you can't just point at a piHole IP...

The solution


diab exists to securely front all your internal and external DNS needs - in conjunction with piHole and Traefik.

Running as a Docker container on a macvlan interface (i.e. with it's own LAN IP) it will provide:

  1. Standard (plaintext) DNS - internally only - forwarded to a DNS service of your choice

  2. DoH - internally and externally - forwarded to a DNS service of your choice

  3. DoT - internally and externally - forwarded to a DNS service of your choice (enabling "Private DNS" on Android)

The assumption here is that the "DNS service of your choice" is already configured (i.e. piHole, or another DoT/DoH/DNSCrypt proxy to an external DNS). diab will just continue plugging into that - so all you need to do is change your DNS IP/host to the new diab IP. If you're using piHole as your DNS - don't worry, we cover that further down...

Whilst diab will be externally available (via DoT, if you want "Private DNS" and/or DoH) - it will only respond to queries it is allowed to. It will reject queries for anything else it's not setup to answer - so whilst it's not "firewalled", it's not useful to anyone else.

By default, it will allow Android mobile devices to resolve client1-5.google.com and connectivitycheck.gstatic.com - to prevent any device using it for Private DNS from displaying "offline" or "no internet" alerts.

Over and above that, you can allow then certain addresses on your domain to respond - i.e. WireGuard.

Get it!

If you want to avail yourself of diab you can grab the Docker Image or view the GitHub repository - the full set of instructions are located there :)