felhom-pve joins the tailnet as a host package (100.70.170.35, expiry disabled); DooPlex already advertised 192.168.0.0/24 via its GitOps k3s tailscale pod (100.107.87.53). ssh felhom-pve now targets the tailnet IP (direct-over-LAN at home, tunnel when away); felhom-pve-lan = LAN fallback. --accept-dns=false on the host. Host converted static->DHCP (reservation keeps .162 at home). Measured: --accept-routes hairpins the local subnet at home -> travel-only opt-in. PBS is offsite (own WireGuard tunnel), needs none of this. Recorded not fixed: controller<->agent plane hard-pinned to 192.168.0.162 (agent listen_addr + guest bootstrap.json) -> not yet portable off-LAN. No code changed. Full doc: documentation/operations/tailscale.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XMForrE4c1wZxd9LukxYVt
6.6 KiB
Tailscale — location-independent access to felhom-pve (the N100)
Added 2026-07-19. Goal: the demo Proxmox host (N100,
felhom-pve) can be taken to a different LAN (e.g. a vacation home) and stay reachable from DooPlex, while its own dependencies keep working. Thessh felhom-pvealias remains the interface — only its transport changed.
Topology (who is what)
| Node | Tailnet name | Tailnet IPv4 | Transport it provides | Managed as |
|---|---|---|---|---|
| DooPlex (192.168.0.180) | dooplex |
100.107.87.53 |
subnet router advertising 192.168.0.0/24; expiry disabled |
k3s pod admin-system/tailscale (hostNetwork, GitOps/ArgoCD) — 157 d old, predates this task |
| N100 (192.168.0.162) | felhom-pve |
100.70.170.35 |
its own node; expiry disabled | host package tailscale (Debian trixie apt repo), tailscaled.service |
Tailnet: nagyfenyvesi.viktor@gmail.com (Tailscale Free). Both nodes run v1.98.x.
ssh felhom-pve now resolves to 100.70.170.35 (see ~/.ssh/config on DooPlex). Tailscale takes
the direct LAN path when both boxes are home (measured: pong … via 192.168.0.162:41641 in 1ms)
and falls back to the tunnel / a DERP relay when the N100 is remote. felhom-pve-lan →
192.168.0.162 is the explicit LAN-only fallback.
Hard rule: --accept-dns=false on the host node
The N100's tailscaled runs with --accept-dns=false (CorpDNS:false). MagicDNS must never
rewrite /etc/resolv.conf: the box relies on pi-hole (192.168.0.250) for split-horizon
(gitea.dooplex.hu → 192.168.0.180). Verified byte-identical after tailscale up. (DooPlex's
containerised node runs TS_ACCEPT_DNS=true, but because it is a pod with its own mount namespace
that only rewrites the container's resolv.conf — the DooPlex host resolv.conf is untouched.)
The accept-routes spike (measured 2026-07-19) — leave it OFF at home
--accept-routes is OFF on felhom-pve and should stay off while the box is on
192.168.0.0/24. Enabling it there was tested and degraded local traffic:
- Tailscale installed
192.168.0.0/24 dev tailscale0into routing table 52 with anip rule 5270: from all lookup 52that outranksmain, so the whole local subnet hijacked onto the tunnel:ip route get 192.168.0.180and…0.250flipped fromvmbr0totailscale0, ping RTT to.180went0.3 ms → ~68 ms, and inbound SSH went asymmetric and stalled. - PBS was unaffected (
10.77.0.1stays onwg-felhom), because PBS does not use this subnet. - Rollback (
tailscale set --accept-routes=false) restored directvmbr0immediately.
When travelling, the N100 is on a different subnet, so accepting 192.168.0.0/24 no longer
overlaps the local net and is safe — it lets the box reach 192.168.0.180/gitea over the tunnel.
Treat it as an opt-in, travel-only toggle you turn on only if you need a home-LAN service (e.g. a
new controller-image pull), and turn back OFF before the box returns home. Management SSH over
100.x is immune to the hairpin either way (that path was used to perform the rollback).
PBS does NOT depend on the home LAN
Contrary to the original assumption, PBS is offsite: storage.cfg targets 10.77.0.1 over the
WireGuard interface wg-felhom whose endpoint is a public Hetzner address (…:443). It works
from any location with internet and needs neither the subnet router nor --accept-routes. This is
why the subnet router is nice-to-have (gitea image pulls while away), not load-bearing.
Key expiry
Disabled on both nodes in the admin console (a node whose key expires mid-trip drops off the tailnet). Confirm on the Machines page: each row shows an Expiry disabled badge.
Rollback / uninstall (host node)
ssh felhom-pve "tailscale set --accept-routes=false" # undo the travel toggle
ssh felhom-pve "tailscale down" # leave the tailnet (reversible: tailscale up)
ssh felhom-pve "systemctl disable --now tailscaled && apt-get purge -y tailscale" # full removal
# then repoint ~/.ssh/config Host felhom-pve back to 192.168.0.162 (or use felhom-pve-lan)
Portability of the N100 itself
- Host network is DHCP (converted 2026-07-19;
iface vmbr0 inet dhcp). At home a DHCP reservation pins MAC68:1d:ef:5d:a6:64→192.168.0.162so home behaviour is unchanged. Revert on the box:cp /root/interfaces.static-revert-20260719 /etc/network/interfaces && ifreload -a. - Guest 9201 is already DHCP.
⚠️ Known blocker — the controller↔agent plane is pinned to 192.168.0.162 (NOT fixed)
felhom-agent binds listen_addr: 192.168.0.162:8443 (in /etc/felhom-agent/agent.json) and guest
9201's /etc/felhom-bootstrap/bootstrap.json points its controller at 192.168.0.162:8443. On a
foreign LAN the host will not have 192.168.0.162, so the agent cannot bind it (agent down) and
the guest cannot reach it. Tailscale and host-DHCP do not fix this (guests bridge at L2). Making
the box fully functional off-LAN needs a design change — bind 0.0.0.0:8443 and give the guest a
stable way to reach the host (e.g. a host-only bridge with a fixed private IP). Until then the N100
is reachable and backs up off-LAN, but its local operator plane is not portable.
Off-LAN DNS note
At a foreign LAN, DHCP repoints the host's resolv.conf at the local resolver, so gitea.dooplex.hu
(pi-hole split-horizon) will not resolve. To pull a controller image while away, either turn on the
travel --accept-routes toggle and add a temporary 192.168.0.180 gitea.dooplex.hu line to
/etc/hosts, or point DNS at 192.168.0.250 over the subnet route. External customer access is via
Cloudflare Tunnel and is unaffected.
Vacation-day checklist (for the operator)
- At the destination, connect the N100 by wired ethernet, power on, wait ~2 min.
- From DooPlex:
tailscale-side — check the pod:sudo kubectl -n admin-system exec deploy/tailscale -- tailscale statusshowsfelhom-pveonline (likely relayed/DERP at first — fine). ssh felhom-pve pveversion— management reachable over the tailnet.ssh felhom-pve "pvesm status | grep -i pbs"— the real off-LAN PBS test (could not be validated at home; PBS rides its own WireGuard tunnel, so it should be green).- Demo URL via Cloudflare Tunnel loads (customer-facing path, independent of all the above).
- If you need a home-LAN service (gitea image pull):
ssh felhom-pve "tailscale set --accept-routes=true"/etc/hostsentry as above — then set it back tofalsebefore the box comes home.
- Expect the controller↔agent plane to be down off-LAN until the pinned-
.162blocker above is fixed.