9.3 KiB
Offline & Remote Access Guide
Last updated: 2026-03-20
How DNS Resolution Works
The homelab uses split-horizon DNS so services are reachable from anywhere — LAN, Tailscale VPN, or the open internet — using the same *.vish.gg domain names.
Three Access Paths
┌──────────────────────────────────────────────────────────────────────┐
│ DNS Query: nb.vish.gg │
├──────────────┬──────────────────┬────────────────────────────────────┤
│ LAN Client │ Tailscale Client│ Internet Client │
│ (at home) │ (travel laptop) │ (phone on cellular) │
├──────────────┼──────────────────┼────────────────────────────────────┤
│ DNS: AdGuard│ DNS: Headscale │ DNS: Cloudflare │
│ (192.168.0 │ MagicDNS → │ (1.1.1.1) │
│ .250) │ AdGuard │ │
├──────────────┼──────────────────┼────────────────────────────────────┤
│ Resolves to:│ Resolves to: │ Resolves to: │
│ 100.85.21.51│ 100.85.21.51 │ 104.21.73.214 (Cloudflare) │
│ (NPM via TS)│ (NPM via TS) │ │
├──────────────┼──────────────────┼────────────────────────────────────┤
│ Path: │ Path: │ Path: │
│ Client → │ Client → │ Client → Cloudflare → │
│ NPM (direct)│ Tailscale → │ Router → NPM → │
│ → backend │ NPM → backend │ backend │
├──────────────┼──────────────────┼────────────────────────────────────┤
│ Latency: │ Latency: │ Latency: │
│ ~1ms │ ~5-50ms │ ~50-100ms │
│ (LAN) │ (Tailscale) │ (Cloudflare roundtrip) │
├──────────────┼──────────────────┼────────────────────────────────────┤
│ Internet │ Internet │ Internet │
│ required? │ required? │ required? │
│ NO │ NO (peer-to-peer│ YES │
│ │ if both on TS) │ │
└──────────────┴──────────────────┴────────────────────────────────────┘
Key: Everything Resolves to 100.85.21.51
All *.vish.gg, *.thevish.io, and *.crista.love domains resolve to 100.85.21.51 (matrix-ubuntu's Tailscale IP) when queried through AdGuard. This is NPM's address on the Tailscale network, reachable from:
- LAN clients — via the router's DHCP DNS (AdGuard at 192.168.0.250)
- Remote Tailscale clients — via Headscale MagicDNS which forwards to AdGuard
- Both paths hit NPM on its Tailscale IP, which works from anywhere on the tailnet
When Internet Goes Down
If your WAN link drops:
| What works | How |
|---|---|
All *.vish.gg services |
AdGuard returns Tailscale IP, NPM proxies locally |
MagicDNS names (atlantis.tail.vish.gg) |
Headscale resolves directly |
| Direct Tailscale IPs (100.x.x.x) | Always work between peers |
| Olares/K8s (k9s, kubectl) | LAN access at 192.168.0.145 |
| What breaks | Why |
|---|---|
| External access (from internet) | Cloudflare can't reach you |
| Cloudflare-only domains without split-horizon rewrite | DNS returns unreachable CF proxy IP |
| Renovate, DDNS updates | Need internet to reach APIs |
| DERP relays for remote peers | Remote Tailscale clients may lose connectivity |
Access from Travel Laptop
Your travel laptop (MSI Prestige) connects via Headscale VPN:
- Join the tailnet:
tailscale up --login-server=https://headscale.vish.gg - DNS is automatic: Headscale pushes AdGuard as the DNS server via MagicDNS
- All domains work:
nb.vish.gg,git.vish.gg, etc. resolve to NPM's Tailscale IP - No VPN split tunneling needed: Only homelab traffic routes through Tailscale
# From the travel laptop:
curl https://nb.vish.gg/ # → 100.85.21.51 (Tailscale) → NPM → backend
curl https://gf.vish.gg/ # → 100.85.21.51 (Tailscale) → NPM → Grafana
ssh homelab.tail.vish.gg # → MagicDNS → direct Tailscale peer
If Headscale Is Down
If the Headscale control server (calypso) is unreachable, already-connected peers maintain their connections. New peers can't join. Use direct Tailscale IPs as fallback:
| Service | Direct URL |
|---|---|
| Grafana | http://100.67.40.126:3300 |
| NetBox | http://100.67.40.126:8443 |
| Portainer | https://100.83.230.112:9443 |
| Gitea | http://100.103.48.78:3052 |
MagicDNS (.tail.vish.gg)
Headscale MagicDNS provides <hostname>.tail.vish.gg for all peers:
| Hostname | Tailscale IP | Use |
|---|---|---|
| atlantis.tail.vish.gg | 100.83.230.112 | NAS, media |
| calypso.tail.vish.gg | 100.103.48.78 | NAS, Gitea, auth |
| homelab.tail.vish.gg | 100.67.40.126 | Monitoring, tools |
| matrix-ubuntu.tail.vish.gg | 100.85.21.51 | NPM, Matrix, Mastodon |
| pve.tail.vish.gg | 100.87.12.28 | Proxmox |
| pi-5.tail.vish.gg | 100.77.151.40 | Uptime Kuma |
| vish-concord-nuc.tail.vish.gg | 100.72.55.21 | Home Assistant, edge |
| setillo.tail.vish.gg | 100.125.0.20 | Remote NAS |
| seattle.tail.vish.gg | 100.82.197.124 | Cloud VPS |
| truenas-scale.tail.vish.gg | 100.75.252.64 | TrueNAS |
Note: MagicDNS only works on devices connected to the Headscale tailnet. It requires the Tailscale client to override the system DNS resolver. Some devices (like pi-5 with AdGuard as DNS) can't resolve .tail.vish.gg names — use Tailscale IPs directly instead.
AdGuard DNS Rewrites (Split-Horizon)
AdGuard on Calypso (192.168.0.250:9080) has wildcard rewrites:
| Domain Pattern | Resolves To | Purpose |
|---|---|---|
*.vish.gg |
100.85.21.51 |
NPM via Tailscale |
*.thevish.io |
100.85.21.51 |
NPM via Tailscale |
*.crista.love |
100.85.21.51 |
NPM via Tailscale |
derp.vish.gg |
192.168.0.250 |
DERP relay (direct) |
derp-atl.vish.gg |
192.168.0.200 |
DERP relay (direct) |
turn.thevish.io |
192.168.0.200 |
TURN server (direct) |
SSL Certificates
All services use Let's Encrypt wildcard certificates (issued via DNS challenge with Cloudflare API):
| Certificate | Domains | Issuer |
|---|---|---|
| Cert 8 | *.vish.gg, vish.gg |
ZeroSSL (via acme.sh) |
| Cert 9 | *.thevish.io, thevish.io |
ZeroSSL (via acme.sh) |
| Cert 10 | *.crista.love, crista.love |
ZeroSSL (via acme.sh) |
These certs are publicly trusted — no certificate warnings on any access path (LAN, Tailscale, or internet).
Certificate Renewal
acme.sh is installed on matrix-ubuntu (/home/test/.acme.sh/) with auto-renewal via cron. To manually renew:
ssh matrix-ubuntu
export CF_Token="REDACTED_TOKEN" # pragma: allowlist secret
~/.acme.sh/acme.sh --renew -d '*.vish.gg' -d 'vish.gg' --force
~/.acme.sh/acme.sh --renew -d '*.thevish.io' -d 'thevish.io' --force
~/.acme.sh/acme.sh --renew -d '*.crista.love' -d 'crista.love' --force
# Then re-upload to NPM (certs need to be uploaded via NPM API or UI)
Quick Reference
I'm at home on WiFi
Just use https://nb.vish.gg — AdGuard resolves to NPM's Tailscale IP, works instantly.
I'm traveling with the laptop
Connect to Headscale tailnet → same URLs work: https://nb.vish.gg
I'm on my phone (no VPN)
Use the public URLs: https://nb.vish.gg → goes through Cloudflare as normal.
Internet is down at home
All services still work from LAN via AdGuard → Tailscale IP → NPM. No Cloudflare dependency.
I need to access a service directly (no NPM)
Use Tailscale IPs: http://100.67.40.126:3300 (Grafana), http://100.83.230.112:9443 (Portainer)
Everything is down — emergency access
SSH via Tailscale: ssh homelab (uses ~/.ssh/config with Tailscale IPs)