Android Private DNS With Adguard Home

Posted on Jul 9, 2025

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.