Files
homelab-optimized/docs/infrastructure/offline-and-remote-access.md
Gitea Mirror Bot 4aacb7184a
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m1s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-03-20 10:15:21 UTC
2026-03-20 10:15:21 +00:00

179 lines
9.3 KiB
Markdown

# 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:
1. **Join the tailnet**: `tailscale up --login-server=https://headscale.vish.gg`
2. **DNS is automatic**: Headscale pushes AdGuard as the DNS server via MagicDNS
3. **All domains work**: `nb.vish.gg`, `git.vish.gg`, etc. resolve to NPM's Tailscale IP
4. **No VPN split tunneling needed**: Only homelab traffic routes through Tailscale
```bash
# 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:
```bash
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)
## Related Documentation
- [Split-Horizon DNS Implementation](split-horizon-dns.md)
- [NPM Migration Plan](npm-migration-to-matrix-ubuntu.md)
- [Authentik SSO](authentik-sso.md)
- [Image Update Guide](../admin/IMAGE_UPDATE_GUIDE.md)