New documentation/operations/nodes.md: HP t740 hardware, disks (SanDisk system SSD 182195804614; Toshiba 1TB NVMe 58BS11AFT8MQ PRESENT AND UNENROLLED, still NTFS, do not touch), the five-NIC map and the trap that cost the first install, and the access path - no SSH key is baked, auth is the hub-vaulted G1 break-glass password. tailscale.md gains demo-hp, the operator-lab-exception warning so a future product-shape audit does not conclude the product ships tailscale, and the --accept-dns evidence: the join omitted the flag, MagicDNS rewrote /etc/resolv.conf, and it was reverted. Harmless at the vacation site, would have bitten silently at home where split-horizon matters. OPEN: key expiry still enabled on demo-hp (2027-01-17) - needs an admin-console toggle or an API token; a pre-auth key cannot do it.
9.1 KiB
Tailscale — location-independent access to the demo nodes (N100 + HP t740)
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 |
HP t740 (demo-hp-bb76ea) |
demo-hp |
100.76.96.79 |
its own node; expiry NOT yet disabled — see below | host package tailscale 1.98.9 (Debian trixie apt repo), tailscaled.service, added 2026-07-21 |
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.
This is an OPERATOR-LAB EXCEPTION, not product shape
Real customer boxes never get tailscale. Customer operator-access is the WireGuard tunnel plus
the H1 OOB path, full stop. Tailscale exists on felhom-pve and demo-hp only because those two are
lab machines that live on LANs the operator does not control.
demo-hp is the confusing one: it is customer-shaped — a normal appliance install, a real
customer record, a real guest, a real day-0 — with tailscale bolted on afterwards by hand. A future
product-shape audit that finds it there must not conclude the product ships it. See
operations/nodes.md.
demo-hp joined 2026-07-21
tailscale up --authkey=file:… --hostname=demo-hp --accept-routes=false, then
tailscale set --accept-dns=false (see the hard rule below — it was needed, and why is worth
reading). Auth was a pre-auth key, passed as --authkey=file:<path> and shredded immediately so it
never appeared in the box's process list. Verified from DooPlex: ping ~40 ms, direct SSH with no
ProxyJump, and the path is direct (37.191.56.193:45127), not a DERP relay.
OPEN: key expiry is still enabled on demo-hp (expires 2027-01-17), unlike the other two
nodes which have it disabled. Disabling it is a per-device admin-console toggle (Machines →
demo-hp → Disable key expiry) or an API call with a tskey-api-… token; a tskey-auth-… pre-auth
key cannot do it (verified: the API returns 401). Until it is toggled the node will drop off the
tailnet on that date and need re-authentication.
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.
On demo-hp this rule was broken and then fixed, which is the useful part of the story. The join
omitted --accept-dns=false, and MagicDNS promptly rewrote /etc/resolv.conf to
nameserver 100.100.100.100 — exactly what this rule forbids. Nothing broke at the vacation site,
because there is no pi-hole there and both gitea.dooplex.hu and hub.felhom.eu resolve publicly
anyway; the damage would have appeared silently when the box comes home, where split-horizon is
what makes gitea.dooplex.hu → 192.168.0.180 local. tailscale set --accept-dns=false restored
nameserver 192.168.0.1 immediately, with the tailnet and the agent unaffected. Pass
--accept-dns=false at join time on any host node; do not rely on noticing afterwards. (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.