All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Major documentation cleanup after VLAN migration completion: - Archive 12 VLAN project docs to archive/vlan-migration/ - Archive 5 done WIP docs (VLAN proposals, AI stack, Fossorial, DNS backup) - Create standing reference docs 08-DNS-ARCHITECTURE and 09-TAILSCALE-VPN - Renumber docs to clean 01-09 sequence with merged CHANGELOG - Update all active docs from stale 192.168.31.x to current VLAN 10 IPs - Fix CSS1 (.10.9→.10.3) and ZX1 (.10.7→.10.4) IPs in hardware inventory - Clean 06-VLAN-DEVICE-ASSIGNMENT: remove migration columns/sections, fix VLAN 25 subnet Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 KiB
11 KiB
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 │
│ ┌──────────────────┐ │
│ │ Quad9 DoH │ ◄── dns.quad9.net/dns-query │
│ │ 9.9.9.9 │ ◄── Quad9 bootstrap │
│ │ 149.112.112.112 │ ◄── Quad9 secondary │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 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)
# 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
# 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
/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
- https://dns.quad9.net/dns-query (Quad9 DoH - malware blocking)
- 9.9.9.9 (Quad9 bootstrap)
- 149.112.112.112 (Quad9 bootstrap secondary)
Bootstrap DNS
- 9.9.9.9
- 149.112.112.112
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
/container print
Check container logs
:log print where topics~"container"
Test DNS resolution
:resolve google.com server=172.17.0.2
Check NAT rules
/ip firewall nat print where comment~"DNS" or comment~"AdGuard"
Scripts
Setup script: scripts/mikrotik-adguard-setup.rsc
Related Documents
- 00-CURRENT-STATE.md - Current infrastructure state
- 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:
# 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).