# DNS Architecture with AdGuard Failover **Created:** 2026-01-31 **Status:** Implemented **Backup:** `adguard-failover-complete-2026-01-31.backup` --- ## Overview Dual AdGuard DNS setup with automatic failover. All DNS queries are filtered through AdGuard for ad-blocking, and if the primary (MikroTik) fails, traffic automatically switches to secondary (Unraid). --- ## Architecture ``` ┌─────────────────────────────────────┐ │ INTERNET │ │ │ │ External clients (DoT/DoH) │ │ dns.xtrm-lab.org:853 (DoT) │ │ dns.xtrm-lab.org:8443 (DoH) │ └──────────────┬──────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ MikroTik hAP ax³ (192.168.10.1) │ │ │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ AdGuard Home (PRIMARY) │ │ │ │ Container: 172.17.0.2 │ │ │ │ Web UI: http://192.168.10.1:3000 │ │ │ │ │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ Filters │ │ Blocklists │ │ Clients │ │ │ │ │ │ (synced) │ │ 143K rules │ │ (synced) │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ Netwatch monitors every 10s │ │ │ │ │ ┌─────────┴─────────┐ │ │ │ │ │ │ Container UP Container DOWN │ │ │ │ │ │ ▼ ▼ │ │ NAT → 172.17.0.2 NAT → 192.168.10.10 │ │ (MikroTik) (Unraid Failover) │ └──────────────────────────────────────────────────────────────────────────────┘ ▲ ▲ ▲ │ │ │ NAT Redirect NAT Redirect NAT Redirect │ │ │ ┌───────┴───────┐ ┌────────┴────────┐ ┌────────┴────────┐ │ VLAN 10 │ │ VLAN 20/25 │ │ VLAN 30/40 │ │ Management │ │ Trusted/Kids │ │ IoT/CatchAll │ │ 192.168.10.x │ │ 192.168.20.x │ │ 192.168.30.x │ │ │ │ 192.168.25.x │ │ 192.168.1.x │ └───────────────┘ └─────────────────┘ └─────────────────┘ ``` --- ## AdGuard Instances | Instance | Role | IP | Port | Web UI | |----------|------|-----|------|--------| | MikroTik | Primary | 172.17.0.2 | 53 | http://192.168.10.1:3000 | | Unraid | Secondary/Failover | 192.168.10.10 | 3000 | http://192.168.10.10:3000 | ### Credentials (Same for Both) | Username | Password | |----------|----------| | jazzymc | 7RqWElENNbZnPW | --- ## DNS Redirect Rules All DNS queries (port 53) from any VLAN are intercepted and redirected: | VLAN | Subnet | Redirected To | |------|--------|---------------| | 10 | 192.168.10.0/24 | 172.17.0.2:53 | | 20 | 192.168.20.0/24 | 172.17.0.2:53 | | 25 | 192.168.25.0/24 | 172.17.0.2:53 | | 30 | 192.168.30.0/24 | 172.17.0.2:53 | | 40 | 192.168.1.0/24 | 172.17.0.2:53 | **Note:** Clients don't need any DNS configuration - even if they use 8.8.8.8, traffic is intercepted by NAT. ### NAT Rules on MikroTik ```routeros # Exception rules (prevent loops) - MUST BE FIRST /ip firewall nat add chain=dstnat action=accept protocol=udp src-address=172.17.0.0/24 dst-port=53 comment="[DNS] Allow MikroTik AdGuard outbound" add chain=dstnat action=accept protocol=udp src-address=192.168.10.10 dst-port=53 comment="[DNS] Allow Unraid AdGuard outbound" # VLAN redirect rules add chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=53 protocol=udp src-address=192.168.10.0/24 dst-port=53 comment="[DNS] VLAN10 Mgmt redirect" add chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=53 protocol=udp src-address=192.168.20.0/24 dst-port=53 comment="[DNS] VLAN20 Trusted redirect" add chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=53 protocol=udp src-address=192.168.25.0/24 dst-port=53 comment="[DNS] VLAN25 Kids redirect" add chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=53 protocol=udp src-address=192.168.30.0/24 dst-port=53 comment="[DNS] VLAN30 IoT redirect" add chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=53 protocol=udp src-address=192.168.1.0/24 dst-port=53 comment="[DNS] VLAN40 CatchAll redirect" # Masquerade for return traffic add chain=srcnat action=masquerade protocol=udp src-address=192.168.10.0/24 dst-address=172.17.0.2 dst-port=53 comment="[DNS] VLAN10 masquerade" # ... (similar for other VLANs) ``` --- ## Automatic Failover ### How It Works 1. **Netwatch** monitors 172.17.0.2 (container IP) every 10 seconds 2. If ping fails for 3 seconds → status changes to "down" 3. **dns-failover-down** script runs → NAT rules switch to Unraid 4. When ping succeeds again → status changes to "up" 5. **dns-failover-up** script runs → NAT rules switch back to MikroTik ### Failover Timeline | Event | Detection Time | Total Switchover | |-------|----------------|------------------| | Container stops | ~10-13 seconds | ~13-16 seconds | | Container recovers | ~10-13 seconds | ~13-16 seconds | ### Failover Scripts ```routeros # dns-failover-down (runs when container is unreachable) /system script add name=dns-failover-down dont-require-permissions=yes source={ :log warning "DNS Failover: Switching to Unraid" /ip firewall nat set [find where comment~"VLAN" and comment~"redirect"] to-addresses=192.168.10.10 to-ports=3000 } # dns-failover-up (runs when container is back) /system script add name=dns-failover-up dont-require-permissions=yes source={ :log info "DNS Failover: Switching back to MikroTik" /ip firewall nat set [find where comment~"VLAN" and comment~"redirect"] to-addresses=172.17.0.2 to-ports=53 } ``` ### Netwatch Configuration ```routeros /tool netwatch add host=172.17.0.2 interval=10s timeout=3s \ up-script=dns-failover-up \ down-script=dns-failover-down \ comment="AdGuard failover monitor" ``` --- ## Sync Configuration Settings are synced from Unraid (source of truth) to MikroTik every 30 minutes. ### What Syncs | Feature | Synced | |---------|--------| | Filter lists (blocklists) | ✅ | | User rules (custom blocks/allows) | ✅ | | Client settings (per-device rules) | ✅ | | Services (blocked services) | ✅ | | Rewrites (custom DNS entries) | ✅ | | DNS server config | ❌ | | DHCP settings | ❌ | | Query logs/stats | ❌ | ### Sync Container ```yaml # /mnt/user/appdata/adguard-sync/adguardhome-sync.yaml cron: "*/30 * * * *" runOnStart: true origin: url: http://192.168.10.10:3000 username: jazzymc password: 7RqWElENNbZnPW replicas: - url: http://192.168.10.1:3000 username: jazzymc password: 7RqWElENNbZnPW features: dns: serverConfig: false accessLists: true rewrites: true filters: true clientSettings: true services: true ``` **Note:** The sync container must be connected to both `dockerproxy` and `br0` networks to reach both AdGuard instances. --- ## Container Configuration (MikroTik) ### Container Details | Setting | Value | |---------|-------| | Image | adguard/adguardhome:latest | | Interface | veth-adguard | | IP | 172.17.0.2/24 | | Gateway | 172.17.0.1 | | Root dir | usb1/adguard/root | | Config mount | usb1/adguard/conf → /opt/adguardhome/conf | | Work mount | usb1/adguard/work → /opt/adguardhome/work | | Start on boot | Yes | ### Container Commands ```routeros # Check status /container print # Start container /container start 0 # Stop container /container stop 0 # View logs /log print where topics~"container" ``` --- ## Upstream DNS Both AdGuard instances use the same upstream: | Upstream | Type | |----------|------| | https://dns.quad9.net/dns-query | Primary (DoH) | | 9.9.9.9 | Bootstrap | | 149.112.112.112 | Bootstrap secondary | --- ## Management | Task | Where to Do It | |------|----------------| | Change blocklists | Unraid AdGuard (syncs to MikroTik) | | Add custom rules | Unraid AdGuard | | Add client settings | Unraid AdGuard | | View query logs | MikroTik AdGuard (real-time) | | Check failover status | MikroTik `/tool netwatch print` | --- ## Troubleshooting ### Check Failover Status ```routeros /tool netwatch print # STATUS should be "up" normally ``` ### Check Current DNS Target ```routeros /ip firewall nat print where comment~"VLAN10 Mgmt redirect" # to-addresses should be 172.17.0.2 (normal) or 192.168.10.10 (failover) ``` ### View Failover Logs ```routeros /log print where message~"Failover" ``` ### Manual Failover Test ```routeros # Stop container (triggers failover) /container stop 0 # Wait 15 seconds, check NAT rules switched to 192.168.10.10 # Start container (triggers recovery) /container start 0 # Wait 15 seconds, check NAT rules switched back to 172.17.0.2 ``` ### DNS Not Working 1. Check container is running: `/container print` 2. Check netwatch status: `/tool netwatch print` 3. Test DNS directly: `:resolve google.com server=172.17.0.2` 4. Check NAT rules: `/ip firewall nat print where comment~"DNS"` ### Sync Not Working ```bash # On Unraid docker logs adguardhome-sync --tail 20 # Check connectivity docker exec adguardhome-sync ping -c 2 192.168.10.10 docker exec adguardhome-sync ping -c 2 192.168.10.1 ``` --- ## Backups | Backup | Description | |--------|-------------| | `pre-adguard-2026-01-31` | Before AdGuard setup | | `adguard-container-running-2026-01-31` | Container working, before NAT | | `adguard-synced-2026-01-31` | After sync configured | | `adguard-failover-complete-2026-01-31` | Final with failover | ### Restore Command ```routeros /system backup load name=adguard-failover-complete-2026-01-31 ``` --- ## Quick Reference ### Normal Operation - DNS queries → MikroTik AdGuard (172.17.0.2) - Ad blocking active - ~143,000 filter rules ### During Failover - DNS queries → Unraid AdGuard (192.168.10.10) - Ad blocking still active (same rules synced) - Automatic, no manual intervention needed ### Recovery - Automatic when container comes back up - NAT rules switch back to MikroTik - No DNS interruption for clients --- **Document Version:** 1.0 **Last Updated:** 2026-01-31