# MikroTik AdGuard Home with DoT/DoH **Status:** Completed **Implemented:** 2026-01-25 --- ## Overview Single DNS endpoint for both internal and external clients with ad blocking and encrypted DNS. ## Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ EXTERNAL │ │ │ │ Mobile/Remote ──► dns.xtrm-lab.org ──► WAN:853 (DoT) │ │ ──► WAN:8443 (DoH) │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ MikroTik hAP ax³ │ │ 192.168.31.1 │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ NAT (DSTNAT) │ │ │ │ WAN:853 ──► 172.17.0.2:853 (DoT) │ │ │ │ WAN:8443 ──► 172.17.0.2:443 (DoH) │ │ │ │ LAN:53 ──► 172.17.0.2:53 (DNS redirect) │ │ │ │ LAN:3000 ──► 172.17.0.2:80 (Web UI) │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ AdGuard Home Container │ │ │ │ 172.17.0.2 (veth-adguard) │ │ │ │ │ │ │ │ Ports: 53 (DNS), 80 (HTTP), 443 (HTTPS), 853 (DoT) │ │ │ │ Storage: usb1/adguard/{conf,work,root} │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ Upstream DNS │ │ ┌──────────────────┐ │ │ │ 192.168.31.4 │ ◄── Unraid AdGuard (primary)│ │ │ 8.8.8.8 │ ◄── Google (fallback) │ │ │ 1.1.1.1 │ ◄── Cloudflare (fallback) │ │ └──────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ INTERNAL │ │ │ │ LAN Clients ──► 192.168.31.1:53 ──► NAT redirect ──► Container │ │ (192.168.31.0/24) │ └─────────────────────────────────────────────────────────────────────┘ ``` ## Network Configuration ### Container Network | Component | IP Address | Interface | |-----------|------------|-----------| | MikroTik (gateway) | 172.17.0.1/24 | veth-adguard | | AdGuard container | 172.17.0.2/24 | veth-adguard | ### Port Mapping | Service | External Port | Internal Target | Protocol | |---------|---------------|-----------------|----------| | DNS | 53 | 172.17.0.2:53 | UDP/TCP | | DoT | 853 | 172.17.0.2:853 | TCP | | DoH | 8443 | 172.17.0.2:443 | TCP | | Web UI | 3000 | 172.17.0.2:80 | TCP | ## Routing & NAT Rules ### DNS Flow for LAN Clients ``` 1. Client (192.168.31.x) sends DNS query to any IP:53 2. DSTNAT rule intercepts and redirects to 172.17.0.2:53 3. SRCNAT masquerade ensures return traffic goes back through MikroTik 4. AdGuard processes query, checks filters 5. If not cached/blocked, forwards to upstream (192.168.31.4 first) 6. Response returns to client ``` ### NAT Rules (in order) ```routeros # 1. Exception rules (must be FIRST to prevent loops) chain=dstnat action=accept protocol=udp src-address=172.17.0.0/24 dst-port=53 comment="Allow MikroTik AdGuard outbound DNS" chain=dstnat action=accept protocol=udp src-address=192.168.31.4 dst-port=53 comment="Allow Unraid AdGuard outbound DNS" chain=dstnat action=accept protocol=tcp src-address=192.168.31.4 dst-port=53 comment="Allow Unraid AdGuard outbound DNS TCP" # 2. LAN DNS redirect chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=53 protocol=udp src-address=192.168.31.0/24 dst-port=53 comment="Redirect DNS to MikroTik AdGuard" chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=53 protocol=tcp src-address=192.168.31.0/24 dst-port=53 comment="Redirect DNS to MikroTik AdGuard TCP" # 3. Masquerade for symmetric routing chain=srcnat action=masquerade protocol=udp src-address=192.168.31.0/24 dst-address=172.17.0.2 dst-port=53 comment="Masquerade DNS to MikroTik AdGuard" chain=srcnat action=masquerade protocol=tcp src-address=192.168.31.0/24 dst-address=172.17.0.2 dst-port=53 comment="Masquerade DNS to MikroTik AdGuard TCP" # 4. External access (DoT/DoH) chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=853 protocol=tcp in-interface=eth1_WAN dst-port=853 comment="DNS over TLS (DoT)" chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=443 protocol=tcp in-interface=eth1_WAN dst-port=8443 comment="DNS over HTTPS (DoH)" # 5. Web UI access chain=dstnat action=dst-nat to-addresses=172.17.0.2 to-ports=80 protocol=tcp dst-address=192.168.31.1 dst-port=3000 comment="AdGuard Web UI" ``` ### Firewall Filter Rules ```routeros # Allow traffic to/from container network chain=input action=accept dst-address=172.17.0.0/24 comment="Allow container network" chain=input action=accept src-address=172.17.0.0/24 comment="Allow from container network" chain=forward action=accept dst-address=172.17.0.0/24 comment="Allow to container network" chain=forward action=accept src-address=172.17.0.0/24 comment="Allow from container network" ``` ### MikroTik DNS Configuration ```routeros /ip dns servers=172.17.0.2 allow-remote-requests=yes ``` ## Container Configuration ### Mounts | Name | Source | Destination | |------|--------|-------------| | agh-config | usb1/adguard/conf | /opt/adguardhome/conf | | agh-work | usb1/adguard/work | /opt/adguardhome/work | ### Container Settings - **Image:** adguard/adguardhome:latest - **Version:** v0.107.71 - **Root dir:** usb1/adguard/root - **DNS:** 8.8.8.8 (for container itself during startup) - **Start on boot:** yes - **Logging:** yes ## TLS Configuration - **Server name:** dns.xtrm-lab.org - **Certificate:** Let's Encrypt (ECDSA) - **Valid until:** 2026-03-10 - **Certificate location:** /mnt/user/appdata/claude-code/certbot/config/live/dns.xtrm-lab.org/ ## AdGuard Settings ### Credentials - **Username:** admin - **Password:** admin123 - **Web UI:** http://192.168.31.1:3000 ### Upstream DNS 1. 192.168.31.4 (Unraid AdGuard - primary, has filter lists) 2. 8.8.8.8 (Google - fallback) 3. 1.1.1.1 (Cloudflare - fallback) ### Bootstrap DNS - 8.8.8.8 - 1.1.1.1 ## Usage ### For LAN Clients No configuration needed - DNS queries are automatically redirected. ### For Android (Private DNS) Settings → Network → Private DNS → dns.xtrm-lab.org ### For iOS (DNS over HTTPS) Use a DNS profile with: https://dns.xtrm-lab.org:8443/dns-query ### For Browsers (DoH) Firefox/Chrome: https://dns.xtrm-lab.org:8443/dns-query ## Troubleshooting ### Check container status ```routeros /container print ``` ### Check container logs ```routeros :log print where topics~"container" ``` ### Test DNS resolution ```routeros :resolve google.com server=172.17.0.2 ``` ### Check NAT rules ```routeros /ip firewall nat print where comment~"DNS" or comment~"AdGuard" ``` ## Scripts Setup script: `scripts/mikrotik-adguard-setup.rsc` ## Related Documents - [00-CURRENT-STATE.md](00-CURRENT-STATE.md) - Current infrastructure state - [incidents/2026-01-25-dns-outbound-blocked-after-mikrotik-restart.md](incidents/2026-01-25-dns-outbound-blocked-after-mikrotik-restart.md) - DNS incident that led to this setup ## Known Issues ### Container fails after restart with "could not load config json" **Symptoms:** - Container shows status `S` (stopped) - Log shows: `could not load config json` **Cause:** Container metadata/config.json corruption after MikroTik restart. **Fix:** ```routeros # 1. Remove broken container /container remove [find name=adguardhome] # 2. Recreate container (will re-download/extract image) /container add remote-image=adguard/adguardhome:latest interface=veth-adguard root-dir=usb1/adguard/root logging=yes start-on-boot=yes dns=8.8.8.8 name=adguardhome # 3. Wait for extraction to complete (check with /container print) # 4. Add mountlists (note: parameter is "mountlists" not "mounts") /container set 0 mountlists=agh-config,agh-work # 5. Start container /container start 0 # 6. Restore MikroTik DNS /ip dns set servers=172.17.0.2 ``` **Note:** The AdGuard configuration in `/opt/adguardhome/conf` is preserved because it is on a separate mount (usb1/adguard/conf).