5.6 KiB
5.6 KiB
AdGuard DNS Mesh
Network-wide ad blocking and split-horizon DNS for all Headscale mesh nodes.
Architecture
Headscale (Calypso)
pushes DNS config to all nodes
│
┌──────┴──────┐
▼ ▼
Calypso AdGuard Atlantis AdGuard
100.103.48.78:53 100.83.230.112:53
(primary) (backup)
│ │
└──────┬──────┘
▼
All Tailscale nodes
(ad blocking + split-horizon)
How It Works
- Headscale pushes two DNS nameservers (Tailscale IPs) to all connected nodes
- Each node resolves DNS through Calypso AdGuard (primary) or Atlantis AdGuard (fallback)
- AdGuard provides ad blocking (filter lists) and split-horizon DNS (38 rewrites for internal services)
- Upstream DNS uses DoH: AdGuard DNS, Cloudflare, Quad9, Google, LibreDNS
Headscale DNS Config
File: /volume1/docker/headscale/config/config.yaml on Calypso
Repo: hosts/synology/calypso/headscale-config.yaml
dns:
magic_dns: true
base_domain: tail.vish.gg
nameservers:
global:
- 100.103.48.78 # Calypso AdGuard (Tailscale IP)
- 100.83.230.112 # Atlantis AdGuard (Tailscale IP)
Using Tailscale IPs (not LAN IPs) ensures remote nodes (Seattle, Jellyfish, mobile devices, GL.iNet routers) can reach the DNS servers.
Split-Horizon DNS Rewrites (38 rules)
Both Calypso and Atlantis AdGuard instances have identical rewrites:
| Domain | Answer | Purpose |
|---|---|---|
*.vish.gg |
100.85.21.51 |
Wildcard → matrix-ubuntu (NPM) |
pt.vish.gg |
192.168.0.154 |
Portainer (direct, not proxied) |
sso.vish.gg |
192.168.0.154 |
Authentik SSO |
git.vish.gg |
192.168.0.154 |
Gitea |
dash.vish.gg |
192.168.0.154 |
Homarr dashboard |
gf.vish.gg |
192.168.0.154 |
Grafana |
headscale.vish.gg |
192.168.0.250 |
Headscale server |
derp.vish.gg |
192.168.0.250 |
DERP relay (Calypso) |
derp-atl.vish.gg |
192.168.0.200 |
DERP relay (Atlantis) |
derp-sea.vish.gg |
100.82.197.124 |
DERP relay (Seattle) |
turn.thevish.io |
192.168.0.200 |
TURN server |
*.tail.vish.gg |
per-node Tailscale IP | MagicDNS node records (12) |
*.vish.local |
per-node Tailscale IP | Local aliases (8) |
*.crista.home |
per-node Tailscale IP | Crista network aliases (2) |
*.thevish.io |
100.85.21.51 |
thevish.io wildcard |
*.crista.love |
100.85.21.51 |
crista.love wildcard |
Node Status
| Node | accept-dns | Split-Horizon | Ad Blocking | Notes |
|---|---|---|---|---|
| homelab-vm | enabled | Yes | Yes | |
| atlantis | enabled | Yes | Yes | |
| seattle | enabled | Yes | Yes | Remote VPS |
| nuc | enabled | Yes | Yes | |
| pi-5 | enabled | Yes | Yes | |
| matrix-ubuntu | enabled | Yes | Yes | |
| jellyfish | enabled | Yes | Yes | No dig/nslookup, verified via python |
| calypso | enabled | N/A | N/A | IS the AdGuard server; Synology can't override resolv.conf |
| setillo | enabled | No | Yes (local) | Synology limitation; has own local AdGuard |
| guava | N/A | N/A | Via LAN | TrueNAS app; uses Calypso AdGuard at 192.168.0.250 on LAN |
Mobile devices, GL.iNet routers, and Home Assistant use default --accept-dns=true and inherit DNS from Headscale automatically.
Rollback
Immediate (~2 min) - revert Headscale DNS to LAN IPs
ssh calypso 'sed -i "s/100.103.48.78/192.168.0.250/" /volume1/docker/headscale/config/config.yaml && \
sed -i "s/100.83.230.112/192.168.68.100/" /volume1/docker/headscale/config/config.yaml'
# Restart headscale via Portainer or:
ssh calypso '/usr/local/bin/docker restart headscale'
Per-node override
# On the affected node:
tailscale set --accept-dns=false
Nuclear - bypass Tailscale DNS entirely
echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf
Symptoms
| Symptom | Cause | Fix |
|---|---|---|
| DNS resolution hangs | Both AdGuard containers down | Restart AdGuard on Calypso/Atlantis |
| Wrong split-horizon (public IP) | Rewrite missing on responding AdGuard | Add missing rewrite via AdGuard UI |
| One node can't resolve | Tailscale tunnel down | tailscale ping calypso to diagnose |
AdGuard Instances
| Instance | Host | LAN IP | Tailscale IP | Web UI | Role |
|---|---|---|---|---|---|
| Calypso | Synology | 192.168.0.250:9080 | 100.103.48.78:9080 | http://192.168.0.250:9080 | Primary |
| Atlantis | Synology | 192.168.0.200:9080 | 100.83.230.112:9080 | http://192.168.0.200:9080 | Backup |
| NUC | Intel NUC | 192.168.68.100:9080 | 100.72.55.21:9080 | http://192.168.68.100:9080 | Local (Concord subnet) |
| Setillo | Synology | 192.168.69.x | 100.125.0.20 | host network | Local (remote site) |
Maintenance
When adding a new split-horizon rewrite, add it to both Calypso and Atlantis AdGuard instances to keep them in sync. Use the AdGuard web UI or API:
# Calypso (via MCP tool or API)
curl -u vish:PASSWORD -X POST http://192.168.0.250:9080/control/rewrite/add \
-H 'Content-Type: application/json' \
-d '{"domain":"new.vish.gg","answer":"192.168.0.154"}'
# Atlantis (same, different host)
curl -u vish:PASSWORD -X POST http://192.168.0.200:9080/control/rewrite/add \
-H 'Content-Type: application/json' \
-d '{"domain":"new.vish.gg","answer":"192.168.0.154"}'
Deployed: 2026-03-31
Config: hosts/synology/calypso/headscale-config.yaml