05 - AdGuard Home + Tailscale DNS
Date: 2025-12-26
System: Proxmox VE 9.1.2
Goal: AdGuard Home DNS server installation with Quad9 DoH/DoT upstream and Tailscale MagicDNS integration
๐ Table of Contents¶
- System overview
- Why a dedicated LXC?
- Avoiding port conflicts
- Creating the LXC
- Installing AdGuard Home
- AdGuard configuration
- Quad9 DoH/DoT setup
- Setting DNS on network devices
- Tailscale DNS integration
- Testing and verification
- Troubleshooting
๐ฅ๏ธ System Overview¶
Current infrastructure:¶
| ID | Type | Name | IP | Services |
|---|---|---|---|---|
| 100 | LXC | docker-host | 192.168.0.110 | Nginx Proxy Manager, Jellyfin, *arr stack, qBittorrent |
| 101 | VM | homeassistant | 192.168.0.202 | Home Assistant OS, Zigbee2MQTT, Mosquitto |
| 102 | LXC | adguard-home | 192.168.0.111 | AdGuard Home DNS |
Network:¶
๐ฏ Why a Dedicated LXC?¶
Problem identification:¶
Port conflicts in Docker (LXC 100):
| Service | Ports | Conflict |
|---|---|---|
| AdGuard Home | 53 (DNS), 80 (WebUI), 443 (DoH/DoT) | โ ๏ธ |
| Nginx Proxy Manager | 80 (HTTP), 443 (HTTPS), 81 (WebUI) | โ ๏ธ |
| Conflict: | 80, 443 | โโ |
If AdGuard were in Docker: - โ Nginx could not listen on port 80/443 - โ Reverse proxy would NOT work - โ SSL termination would NOT work
SOLUTION: Dedicated LXC!¶
Advantages:
โ
Port isolation - No conflict with Nginx
โ
Static IP - Easy DHCP configuration (192.168.0.111)
โ
Network accessibility - All devices (physical machines, Docker, VM) can use it
โ
Independent - LXC stops/restarts โ does not affect Docker or HA
โ
Easy backup - Proxmox vzdump
โ
Lightweight - LXC has no VM overhead (512MB RAM is enough!)
โ
Boot order - Starts first (other services can use DNS)
๐๏ธ Architecture¶
Full DNS chain:¶
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Router (192.168.0.1) โ
โ DHCP DNS server: 192.168.0.111 (AdGuard) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ LXC 102 โ โ LXC 100 โ โ VM 101 โ
โ AdGuard Home โ โ Docker Stack โ โ Home Assistantโ
โ 192.168.0.111 โ โ 192.168.0.110 โ โ 192.168.0.202 โ
โ โ โ โ โ โ
โ Port 53 (DNS) โ โ Nginx (80/443)โ โ HA + Z2M โ
โ Port 80 (UI) โ โ Jellyfin, *arrโ โ โ
โ โ โ DNSโ111 โ
โ โ DNSโ111 โ
โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ
Upstream DNS
โ
โโโโโโโโโโโโโโโโโ
โ Quad9 DoH/DoT โ
โ dns.quad9.net โ
โ ๐ Encrypted โ
โ ๐ก๏ธ Malware โ
โโโโโโโโโโโโโโโโโ
๐ฆ Creating the LXC¶
Proxmox WebUI:¶
Create CT:
General:
CT ID: 102
Hostname: adguard-home
Password: [secure password]
Template:
Storage: local
Template: Debian 12
Disks:
Storage: local-lvm
Disk size: 8GB
After usage:
OS + AdGuard: ~1.5-2GB
Free: ~6GB โ
Thin provisioning: Only ~2GB physical
CPU:
Cores: 1
Sufficient because:
DNS queries are fast
AdGuard is lightweight
No heavy processing
Memory:
Memory: 512MB
Swap: 512MB
Sufficient because:
AdGuard ~100-200MB RAM
Query cache is minimal
No heavy load
Network:
Bridge: vmbr0
Static IP: 192.168.0.111/24
Gateway: 192.168.0.1
DNS: 1.1.1.1 (temporary, later will use itself)
DNS:
DNS servers: 1.1.1.1
Options:
Start at boot: โ
ON
Start order: 1 (starts first!)
Start delay: 10 sec (so DNS is ready before other LXC/VMs start)
Confirm โ Create
๐ฅ Installing AdGuard Home¶
Open LXC Console:¶
Proxmox WebUI:
1. 102 (adguard-home) โ Console
2. Start LXC
3. Login: root + password
Installation:¶
# System update
apt update && apt upgrade -y
# Install curl
apt install curl wget htop nano -y
# AdGuard Home official install script
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
# Check service
systemctl status AdGuardHome
# โ AdGuardHome.service - AdGuard Home
# Active: active (running) โ
# Port check
ss -tulpn | grep -E '53|3000'
# tcp LISTEN 0.0.0.0:53 โ
DNS
# tcp LISTEN 0.0.0.0:3000 โ
WebUI
# IP address
ip addr show eth0 | grep inet
# inet 192.168.0.111/24 โ
๐ AdGuard Configuration¶
Initial Setup Wizard:¶
WebUI: http://192.168.0.111:3000
Steps:
-
Welcome โ Next
-
Admin Web Interface:
- All interfaces โ
- Port:
80(change from 3000!)- WHY? Port 80 is more convenient
- NO conflict! Nginx is in LXC 100!
-
Next
-
DNS Server:
- All interfaces โ
- Port:
53โ -
Next
-
Authentication:
- Username:
admin - Password: [secure password]
-
Next
-
Complete โ Open Dashboard
NEW URL: http://192.168.0.111 (no more :3000!)
๐ Quad9 DoH/DoT Setup¶
Why Quad9?¶
Advantages:
โ
Privacy-focused - Does not log IP addresses
โ
Security - Blocks malware/phishing domains (20+ threat intel)
โ
GDPR compliant - Headquartered in Switzerland
โ
Non-profit - No ads/tracking
โ
DoH/DoT support - Encrypted DNS
Quad9 vs Cloudflare vs Google:
| Provider | Latency | Privacy | Security | Headquarters |
|---|---|---|---|---|
| Quad9 | ~15-20ms | โ โ โ | โ โ โ Malware | ๐จ๐ญ Switzerland |
| Cloudflare | ~10-15ms | โ โ | โ | ๐บ๐ธ USA |
| ~10-15ms | โ ๏ธ Logs | โ | ๐บ๐ธ USA |
Setting upstream DNS:¶
AdGuard WebUI โ Settings โ DNS settings:
Upstream DNS servers:
Explanation: - DoH (DNS over HTTPS): Port 443, full encryption - DoT (DNS over TLS): Port 853, fast encryption - dns11: ECS support (geo-location hint, faster CDN)
Bootstrap DNS servers:
WHY DO WE NEED BOOTSTRAP?
Bootstrap DNS resolves the dns.quad9.net domain name via plain DNS so the DoH/DoT connection can be established!
Process:
1. AdGuard starts โ needs DoH โ what's the IP of dns.quad9.net?
2. Bootstrap DNS (9.9.9.9) โ dns.quad9.net = 9.9.9.9 โ
3. DoH connection: https://dns.quad9.net/dns-query โ
Private reverse DNS servers:
(Local network reverse DNS)
DNS server configuration:
โ
Enable DNSSEC (DNS security)
โ
Enable EDO (Extended DNS Optimizations)
โ
Enable parallel requests (faster)
โ ๏ธ Disable IPv6 (if no IPv6 network)
Apply
Test upstreams:
Click "Test upstreams" button
Result:
โ
https://dns.quad9.net/dns-query - OK (15 ms)
โ
https://dns11.quad9.net/dns-query - OK (18 ms)
โ
tls://dns.quad9.net - OK (12 ms)
All green? โ WORKING!
Adding blocklists:¶
Filters โ DNS blocklists:
Default: - โ AdGuard DNS filter (~450k rules)
To add:
OISD Basic:
Dan Pollock's List:
AdAway:
Apply โ Update filters now
Total: ~500,000-600,000 rules โ
Extra settings:¶
Settings โ General settings:
Filtering: - โ Enable Safe Browsing - โ ๏ธ Enable Parental Control (if you have children)
Query logs: - Retention: 7 days - โ ๏ธ Anonymize client IP (if maximum privacy is needed)
Statistics: - Retention: 90 days
Apply
๐ Setting DNS on Network Devices¶
1. Router DHCP DNS (MOST IMPORTANT!):¶
Router admin panel (192.168.0.1):
DHCP Server / LAN settings:
BEFORE:
AFTER:
Save โ DHCP Server Restart
Result: - All new DHCP clients โ AdGuard DNS - Existing machines โ DHCP renew required!
2. Docker containers (LXC 100):¶
File contents:
{
"dns": ["192.168.0.111", "1.1.1.1"],
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Docker restart:
systemctl restart docker
# Verify
docker run --rm alpine nslookup google.com
# Server: 192.168.0.111 โ
3. Home Assistant (VM 101):¶
Automatic (DHCP): - HA OS automatically uses the network DNS - Router DHCP โ 192.168.0.111 โ
Manual (if static IP):
HA Terminal & SSH:
OR WebUI:
- Settings โ System โ Network
- DNS servers: 192.168.0.111, 1.1.1.1
4. Windows machines:¶
Automatic (DHCP):
Manual (static IP):
1. Network Adapter Properties
2. IPv4 Properties
3. Preferred DNS: 192.168.0.111
4. Alternate DNS: 1.1.1.1
5. OK
5. LXC boot order (CRITICAL!):¶
PROBLEM: Proxmox boots โ AdGuard not yet up โ DNS fails!
SOLUTION: Boot order + delay
# Proxmox host
pct set 102 -onboot 1 -startup order=1,up=10
pct set 100 -startup order=2,up=5
pct set 101 -startup order=3,up=5
Result:
1. Proxmox boot
2. LXC 102 (AdGuard) START โ 10 sec wait
3. AdGuard DNS ready โ
4. LXC 100 (Docker) START โ uses AdGuard โ
5. VM 101 (HA) START โ uses AdGuard โ
๐ Tailscale DNS Integration¶
Problem identification:¶
Proxmox host DNS:
cat /etc/resolv.conf
# resolv.conf(5) file generated by tailscale
# DO NOT EDIT THIS FILE BY HAND
nameserver 100.100.100.100 โ Tailscale MagicDNS
search YOUR_TAILSCALE_NET.ts.net homelab.local
Tailscale automatically overrides DNS!
100.100.100.100 = Tailscale MagicDNS (split DNS, hostname resolution)
SOLUTION: Tailscale Global Nameservers!¶
Tailscale Admin Console:
Configuration:
Global nameservers:
1. Add nameserver: 192.168.0.111 (AdGuard)
2. Add nameserver: 1.1.1.1 (fallback)
3. Save
Result:
Proxmox โ Tailscale MagicDNS (100.100.100.100)
โ Upstream: AdGuard (192.168.0.111) โ
โ Upstream: Quad9 DoH โ
BEST OF BOTH WORLDS:
- โ
Tailscale hostnames work (*.YOUR_TAILSCALE_NET.ts.net)
- โ
AdGuard blocking works
- โ
Quad9 encryption works
Do NOT modify resolv.conf!¶
โ ๏ธ IMPORTANT:
# DO NOT EDIT THIS:
/etc/resolv.conf
# Tailscale auto-generates it!
# If you modify it โ it will be overwritten!
LEAVE IT AS:
Set upstream in: Tailscale Admin Console! โ
๐งช Testing and Verification¶
1. Does DNS work?¶
Windows/Linux:
nslookup google.com
# Expected result:
Server: adguard-home
Address: 192.168.0.111 โ
Name: google.com
Address: 142.250.185.46
2. Does it block?¶
Test ad domain:
nslookup doubleclick.net
# Expected result:
Server: adguard-home
Address: 192.168.0.111
Name: doubleclick.net
Address: 0.0.0.0 โ BLOCKED! โ
In browser:
Result: Ads blocked! โ
3. AdGuard Dashboard:¶
http://192.168.0.111
Query Log: - DNS requests visible - Blocked: red โ - Allowed: green โ
Dashboard stats: - Queries (24h): increasing - Blocked by filters: ~20-40% (normal) - Top clients: list of devices
Top clients check:
192.168.0.109 (Proxmox host) โ
192.168.0.110 (Docker LXC) โ
192.168.0.202 (HA OS VM) โ
192.168.0.XXX (Windows/Phone) โ
4. DNS Leak Test:¶
In browser:
Extended test
CORRECT result:
INCORRECT result (ISP visible): - โ ๏ธ AdGuard upstream not set to Quad9 - โ ๏ธ Browser using its own DoH (Chrome/Firefox setting) - โ ๏ธ Router DHCP DNS not yet updated
5. Does DoH/DoT work?¶
LXC Console:
pct enter 102
# Port 53 (plain DNS) โ NOT in use!
tcpdump -i eth0 port 53 -n
# (No traffic, because DoH/DoT uses 443/853!)
# Port 443 (DoH) โ HAS traffic!
tcpdump -i eth0 port 443 -n
# (HTTPS traffic to Quad9 is visible!)
โ Encrypted DNS working! ๐
โ Troubleshooting¶
Problem 1: DNS not working¶
Symptom: nslookup google.com โ timeout
Check:
# Is AdGuard running?
pct enter 102
systemctl status AdGuardHome
# Active (running)? โ
# Is port 53 listening?
ss -tulpn | grep :53
# 0.0.0.0:53 LISTEN โ
# Firewall?
iptables -L -n | grep DROP
# No DROP rule? โ
Solution:
Problem 2: Upstream DNS fail¶
Symptom: AdGuard โ Settings โ Test upstreams โ red X
Check:
# DNS test from LXC
dig @9.9.9.9 google.com
# Working? โ
# Resolve Quad9 hostname
dig dns.quad9.net
# IP: 9.9.9.9 โ
# HTTPS test
curl -I https://dns.quad9.net/dns-query
# HTTP/2 200 โ
Solution: - Check bootstrap DNS (is 9.9.9.9 configured?) - Does internet connection work? - Is firewall port 443/853 open?
Problem 3: Browser bypasses AdGuard¶
Symptom: DNS leak test โ Cloudflare visible, NOT Quad9
CAUSE: Browser built-in DoH!
Chrome/Edge: - Settings โ Privacy โ Security - Use secure DNS โ OFF โ
Firefox: - Settings โ Privacy & Security - DNS over HTTPS โ OFF โ
Problem 4: AdGuard LXC stops during boot¶
Symptom: DNS not working after Proxmox boot
CAUSE: Wrong boot order or no delay
Solution:
pct set 102 -onboot 1 -startup order=1,up=10
pct set 100 -startup order=2,up=5
pct set 101 -startup order=3,up=5
AND fallback DNS everywhere:
Problem 5: Tailscale overrides DNS¶
Symptom: cat /etc/resolv.conf โ 100.100.100.100, cannot be modified
CAUSE: Tailscale auto-generates it
SOLUTION: Do NOT modify resolv.conf!
Instead: - Tailscale Admin Console โ DNS โ Global nameservers - Add: 192.168.0.111
๐ Final Configuration Summary¶
LXC 102 - AdGuard Home:¶
IP: 192.168.0.111
Port 53: DNS server
Port 80: WebUI
Upstream DNS: Quad9 DoH/DoT
Bootstrap DNS: 9.9.9.9, 149.112.112.112, 1.1.1.1
Blocklists: ~500,000 rules
Proxmox Host:¶
/etc/resolv.conf: 100.100.100.100 (Tailscale MagicDNS)
โ Upstream: 192.168.0.111 (AdGuard - Tailscale Admin Console)
โ Upstream: Quad9 DoH
LXC 100 - Docker:¶
/etc/docker/daemon.json:
{
"dns": ["192.168.0.111", "1.1.1.1"]
}
Docker containers โ AdGuard โ Quad9 DoH โ
VM 101 - HA OS:¶
DHCP DNS: 192.168.0.111 (automatic)
OR
Manual DNS: 192.168.0.111, 1.1.1.1
HA โ AdGuard โ Quad9 DoH โ
Router DHCP:¶
Tailscale:¶
Admin Console โ DNS โ Global nameservers:
- 192.168.0.111 (AdGuard)
- 1.1.1.1 (Cloudflare fallback)
MagicDNS: 100.100.100.100
Search domains: YOUR_TAILSCALE_NET.ts.net, homelab.local
๐ก๏ธ Protection Layers¶
Full DNS Security Stack:
1. ๐ Quad9 DoH/DoT
- Encrypted DNS (ISP cannot see)
- Malware/phishing blocking (20+ threat intel)
- Privacy (no logs, Switzerland)
2. ๐ซ AdGuard Home
- Ad blocking (~500k rules)
- Local DNS cache (faster)
- Query logging (troubleshooting)
- Custom blocklists/allowlists
3. ๐ Tailscale MagicDNS
- Private hostname resolution
- Split DNS (Tailscale network + public)
- Secure mesh networking
4. ๐ Local network
- Single DNS server (192.168.0.111)
- Fallback DNS (1.1.1.1)
- Centralized management
๐ Performance¶
Expected metrics:
DNS query latency:
- Local cache hit: ~1-2ms โก
- AdGuard cache miss: ~15-20ms (Quad9)
- Blocked domain: <1ms (instant) โก
Blocking effectiveness:
- Ads: ~30-40%
- Malware/phishing: automatic
- Privacy tracking: ~20-30%
Resource usage (LXC 102):
- CPU: <5% (idle), ~10-20% (active)
- RAM: ~150-250MB / 512MB
- Disk: ~2GB / 8GB
๐ง Useful Commands¶
AdGuard management:¶
# Service control
systemctl status AdGuardHome
systemctl restart AdGuardHome
systemctl stop AdGuardHome
# Config file
nano /opt/AdGuardHome/AdGuardHome.yaml
# Logs
journalctl -u AdGuardHome -f
DNS testing:¶
# Basic query
nslookup google.com
dig google.com
# Specific DNS server
nslookup google.com 192.168.0.111
dig @192.168.0.111 google.com
# DNS trace
dig +trace google.com
# Reverse DNS
nslookup 192.168.0.111
Network debugging:¶
# Port check
ss -tulpn | grep -E '53|80|443'
# DNS traffic capture
tcpdump -i eth0 port 53 -vv
tcpdump -i eth0 port 443 -vv
# Connection test
telnet 192.168.0.111 53
curl -I http://192.168.0.111
LXC management:¶
# Start/Stop
pct start 102
pct stop 102
pct reboot 102
# Console
pct enter 102
# Status
pct status 102
# Resource usage
pct exec 102 -- htop
๐ฏ Best Practices¶
1. Always have a fallback DNS!¶
On EVERY device:
Primary DNS: 192.168.0.111 (AdGuard)
Secondary DNS: 1.1.1.1 (Cloudflare fallback)
Why?
- AdGuard stops โ fallback takes over โ
- During boot AdGuard not yet up โ fallback works โ
- Emergency โ no DNS blackout โ
2. Correct boot order configuration:¶
LXC 102 (AdGuard): order=1, up=10
LXC 100 (Docker): order=2, up=5
VM 101 (HA): order=3, up=5
Proxmox boot:
1. AdGuard starts FIRST โ 10 sec delay
2. DNS ready โ
3. Docker/HA start โ DNS works โ
3. Regular maintenance:¶
Weekly:
- AdGuard Dashboard stats review
- Blocklist update (auto, verify)
- Query Log review (suspicious activity?)
Monthly:
- AdGuard update check
- LXC backup (Proxmox vzdump)
- Disk usage check (df -h)
Semi-annually:
- Blocklist cleanup (redundant lists?)
- Custom rules review
- Performance tuning
4. Monitoring:¶
Watch AdGuard Dashboard:
http://192.168.0.111
Metrics:
- Queries/day: increasing?
- Blocked %: ~30-40% is normal
- Top blocked domains: ad trackers?
- Top clients: all devices visible?
Proxmox monitoring:
Proxmox WebUI โ LXC 102:
- CPU usage: <20%
- RAM usage: <50% (256MB / 512MB)
- Disk usage: <30% (2GB / 8GB)
5. Backup strategy:¶
Proxmox backup (LXC):
# Manual backup
vzdump 102 --storage backup-hdd --mode snapshot --compress zstd
# Automatic (Datacenter โ Backup)
Schedule: daily 02:00
Storage: backup-hdd
Retention: Keep last 7
AdGuard config export:
๐ Summary¶
What we achieved:
โ
Dedicated AdGuard Home LXC (192.168.0.111)
โ
Port conflicts resolved (Nginx + AdGuard working together)
โ
Quad9 DoH/DoT upstream (encrypted DNS)
โ
~500k blocklist rules (ad + malware blocking)
โ
Tailscale DNS integration (MagicDNS + AdGuard)
โ
Fallback DNS on every device (1.1.1.1)
โ
Boot order optimized (AdGuard starts first)
โ
Full network protection (all devices use it)
Protection levels:
- ๐ Privacy: Quad9 DoH (ISP cannot see DNS)
- ๐ก๏ธ Security: Quad9 malware blocking + AdGuard filtering
- ๐ซ Ad-blocking: ~500k rules, ~30-40% blocked
- ๐ Visibility: Query logs, statistics, dashboard
- โก Performance: Local cache, <20ms latency
FULL DNS SECURITY STACK WORKING! ๐โจ
Created: 2025-12-26
System: Proxmox VE 9.1.2 / AdGuard Home v0.107+ / Tailscale
Version: 1.0