Quick Start: Spin Up DoQ and DoH3 in 5 Minutes
Legacy encrypted DNS protocols like DoT and DoH rely on rigid TCP handshakes. Modern alternatives—DNS over QUIC (DoQ) and DNS over HTTP/3 (DoH3)—switch to UDP-based QUIC instead. This switch wipes out head-of-line blocking on lossy connections and shaves 30 to 80 ms off initial query latencies. Setting up a private recursive resolver on Debian or Ubuntu takes under five minutes.
First, pull down the official AdGuard Home binary installer:
# Download and run the official installer script
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
# Disable systemd-resolved DNSStubListener to free up port 53
sudo sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved
QUIC handshakes mandate valid TLS certificates. If you own a registered domain, generate a free Let’s Encrypt certificate using certbot in standalone mode (make sure port 80 is temporarily open):
sudo apt update && sudo apt install -y certbot
sudo certbot certonly --standalone -d dns.example.com --agree-tos -m [email protected] --non-interactive
Point your browser to http://<your-server-ip>:3000 and step through the initial web wizard. Once you reach the dashboard, head to Settings > Encryption settings. Check Enable Encryption, enter your server name (dns.example.com), and point the interface to your certificate files:
Certificate file: /etc/letsencrypt/live/dns.example.com/fullchain.pem
Private key file: /etc/letsencrypt/live/dns.example.com/privkey.pem
AdGuard Home immediately binds DoQ to UDP port 853 and DoH3 to UDP port 443 alongside standard HTTPS. Punch both ports through your firewall right away:
sudo ufw allow 853/udp comment 'DNS over QUIC (DoQ)'
sudo ufw allow 443/udp comment 'HTTP/3 and DoH3'
sudo ufw reload
Deep Dive: Why QUIC Solves Head-of-Line Blocking
Standard DoT (TCP 853) and DoH (TCP 443) run on top of TLS 1.3 over TCP. A clean connection requires a 3-way TCP handshake (1 RTT) followed by the TLS key exchange (another 1 RTT). When a mobile user hits spotty cellular coverage with a modest 2% packet loss rate, TCP halts every concurrent DNS request until the dropped segment arrives. This bottleneck—head-of-line (HoL) blocking—can inflate page load times by hundreds of milliseconds.
QUIC tackles this architectural flaw by moving the entire transport to UDP:
- Zero Round-Trip Time (0-RTT): Repeat clients skip the dance. By caching crypto session tickets from prior queries, devices fire off DNS payloads on their very first packet.
- Independent Multi-Streaming: Modern media-heavy sites often trigger 30 to 60 distinct domain lookups at once. If packet #4 drops during a lookup for a tracker, the other 59 DNS queries continue resolving without a hitch.
- Seamless Connection Migration: Walk past your front door, and your phone swaps Wi-Fi for 5G. Under TCP, that IP address shift severs every socket and forces renegotiation. QUIC relies on arbitrary 64-bit Connection IDs rather than source IPs. The resolution stream stays alive without dropping a single packet.
Under RFC 9250, native DoQ runs on UDP port 853. DNS over HTTP/3 encapsulates binary DNS frames inside HTTP/3 request streams on UDP port 443. For field engineers maintaining branch offices over flaky satellite or LTE uplinks, migrating to UDP-based resolvers produces an immediate drop in P99 query latency.
Advanced Usage: Tuning AdGuardHome.yaml and Testing Protocols
The GUI gets you running, but power users belong in the configuration file. Editing /opt/AdGuardHome/AdGuardHome.yaml unlocks granular socket buffering, fine-grained TTL overrides, and upstream DoQ forwarding.
Hardening the Core Configuration
Always shut down the daemon before editing its configuration directly:
sudo systemctl stop AdGuardHome
sudo nano /opt/AdGuardHome/AdGuardHome.yaml
Adjust your dns and tls stanzas to route upstreams through fast DoQ and DoH3 endpoints, and dial in cache controls:
dns:
bind_hosts:
- 0.0.0.0
port: 53
upstream_dns:
# Forward lookups to upstream DoQ and DoH3 resolvers
- quic://dns.adguard-dns.com
- h3://cloudflare-dns.com/dns-query
fastest_addr: true
cache_size: 67108864 # 64 MB in-memory cache (~250,000 cached records)
cache_ttl_min: 300 # Enforce a 5-minute minimum TTL
cache_ttl_max: 86400 # Cap records at 24 hours
tls:
enabled: true
server_name: dns.example.com
force_https: false
port_https: 443
port_dns_over_quic: 853
certificate_path: /etc/letsencrypt/live/dns.example.com/fullchain.pem
private_key_path: /etc/letsencrypt/live/dns.example.com/privkey.pem
strict_sni_check: true
Bring the service back up and inspect system logs to confirm the QUIC listeners initialized cleanly:
sudo systemctl start AdGuardHome
sudo journalctl -u AdGuardHome -n 50 --no-pager | grep -i quic
Benchmarking Queries from the Command Line
Traditional tools like dig, drill, and nslookup don’t speak QUIC. Nathan Sales’ open-source q client fills this void, handling DoQ, DoH3, and classical protocols out of the box:
# Download and install the precompiled binary
wget https://github.com/natesales/q/releases/download/v0.19.2/q_0.19.2_linux_amd64.tar.gz
tar -xvf q_0.19.2_linux_amd64.tar.gz
sudo mv q /usr/local/bin/
# Query via DNS over QUIC
q @quic://dns.example.com example.com A
# Query via DNS over HTTP/3
q @h3://dns.example.com/dns-query example.com AAAA
Check the bottom lines of the terminal response. You should see Protocol: QUIC alongside round-trip latencies dropping under 15 ms on warm 0-RTT connections.
Practical Tips for Production Reliability
1. Maximize UDP Socket Receive Buffers
Default Linux network buffers are too small for high-throughput QUIC. Under heavy microbursts, the kernel quietly drops incoming UDP frames before AdGuard Home ever reads them. Boost socket memory allocation by creating /etc/sysctl.d/99-quic.conf:
cat << 'EOF' | sudo tee /etc/sysctl.d/99-quic.conf
net.core.rmem_max = 7500000
net.core.wmem_max = 7500000
net.core.rmem_default = 262144
net.core.wmem_default = 262144
EOF
sudo sysctl --system
2. Automate Zero-Downtime Certificate Reloads
Let’s Encrypt certificates expire every 90 days. When Certbot pulls down a fresh certificate, AdGuard Home needs a gentle reload to pick up the new keypair. Place an automated deploy hook inside Certbot’s post-renewal directory:
cat << 'EOF' | sudo tee /etc/letsencrypt/renewal-hooks/post/adguard-reload.sh
#!/usr/bin/env bash
systemctl restart AdGuardHome
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/adguard-reload.sh
3. Work Around Hostile ISP and Wi-Fi Filtering
Airport Wi-Fi networks, hotel captive portals, and restrictive corporate gateways routinely block outgoing UDP traffic on port 853. Don’t leave your remote devices stranded:
- Deploy mobile configuration profiles (such as iOS
.mobileconfigfiles or Android Private DNS) with DoH3 on port 443 configured as the priority fallback. Enterprise firewalls rarely touch UDP port 443 because doing so breaks Google services, YouTube streaming, and Cloudflare-backed CDNs. - If an upstream ISP drops raw DoQ packets, bind an alternative listener port in your
AdGuardHome.yaml(such as UDP port 8853) or map an eBPFiptablesredirect rule on your edge router.

