Android Private DNS With Adguard Home
Personally, I see two main reasons why someone would want to run their own AdGuard DNS server:
- Block ads & trackers on any devices (eg TVs) in your home network
- Encrypt your DNS queries (it’s 2025 after all)
But here’s the thing: ideally, you also benefit from both of these advantages when being on the go with your phone. This is especially true because you might spend more time in networks you don’t trust that much (but don’t want to bother with running an always-on-VPN).
Luckily, Android makes this easy with their “private DNS” setting — something you still can’t do out-of-the-box on macOS… (Windows 11 brought support for DoH)
Prerequisites
- You have AdGuard Home running
- You have a domain pointing to its IP (either via a static IP or DynDNS)
Introduction
Android’s Private DNS feature doesn’t use DNS over HTTPS (DoH) but DNS over TLS (DoT). Luckily, AdGuard supports both of them out of the box! But there is one caveat: Some networks might block port 853 that is used for DoT, and you’ll see the dreaded “Cannot connect to private DNS” error notification.
The main building blocks for configuring Android Private DNS to connect to the AdGuard Home instance in your homelab are as follows
- Get a TLS certificate (and make sure it renews)
- Enable DNS over TLS in AdGuard
- Configure your router & phone
Get a TLS certificate
As the name DNS over TLS implies, we require a TLS certificate. The following guide is an extension of AdGuard’s own documentation.
We’ll get and renew certificates on the same host as AdGuard is running, because it needs to have access to them to terminate the DNS requests. You can use any ACME-compatible client, this uses lego as an example and a little helper script for downloading and running it.
mkdir -p /opt/tls && cd /opt/tls
curl -s https://raw.githubusercontent.com/ameshkov/legoagh/master/lego.sh --output lego.sh
chmod +x lego.sh
Ideally, we use the DNS challenge, so adapt the following environment variables to your DNS provider (docs):
touch renew.sh && chmod +x renew.sh && vim renew.sh
And configure lego:
DOMAIN_NAME="example.org" EMAIL="you@email" DNS_PROVIDER="cloudflare" CLOUDFLARE_DNS_API_TOKEN="yourapitoken" ./lego.sh
Run it and note the path to the cert and key files.
Since this Let’s Encrypt certificate will expire after 3 months, we want to ensure to renew it beforehand. Hence, add the renew script to your crontab:
crontab -e
# enter
0 8 1 * * /opt/tls/renew.sh # renew on first day of month
Enable DNS over TLS in AdGuard
In your AdGuard web UI, go to Settings > Encryption settings and check “Enable Encryption”.
Scroll down and provide the path to the TLS certificate and key.
Configure your router & phone
As mentioned, DNS over TLS uses port 853 (instead of port 53 like the plaintext DNS), so you’ll want to forward that port from your router to your AdGuard host.
Hardening
Since you now exposed your AdGuard instance publicly on the internet, make sure to follow some basic hardening best practices.
- don’t run AdGuard on the same host as other important services
- don’t run AdGuard as a privileged LXC (UID 0 inside = UID 0 on host)
- keep it updated
- harden your network, e.g. put AdGuard into a VLAN or setup firewall rules that restrict the communication to other hosts in the network
- don’t mount any network shares into the container
This list is not exhaustive — consider it a starting point for your own research.