All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Both AdGuard instances now use Quad9 DoH (dns.quad9.net) - Bootstrap DNS: 9.9.9.9, 149.112.112.112 - New 02-PORT-UTILIZATION.md with ASCII diagrams for all devices - Fixed Tailscale container DNS and route configuration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
276 lines
11 KiB
Markdown
276 lines
11 KiB
Markdown
# 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)
|
|
|
|
```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. https://dns.quad9.net/dns-query (Quad9 DoH - malware blocking)
|
|
2. 9.9.9.9 (Quad9 bootstrap)
|
|
3. 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
|
|
```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).
|