Architecture Decision Record

ADR 015: A Tailscale Subnet Router for Private Remote Access

A deliberate exception to "Git is the only way in" — remote access lives outside Kubernetes, because it has to work when the cluster doesn't.

Status: Accepted  ·  Date: Aug 2026  ·  ← All ADRs


Context

Until now the platform had exactly one way in from outside the house: a Cloudflare Tunnel fronting three deliberately public hostnames. That is the right tool for publishing things — it terminates at an Istio gateway, it’s WAF-protected, and it exposes precisely what I chose to expose.

It is the wrong tool for me getting to the platform. Administering the lab remotely means reaching the Proxmox UIs, Vault, the Talos API, the Synology, the UniFi controller — none of which should ever be public, WAF or not. The options:

I really liked the thought of Tailscale and have read many articles on it by home-labbers just like me. It has a generous free tier that more than meets my needs — and it just worked, on the first try. I’d already spent an afternoon trying to get the same private access out of Cloudflare and never got it to do exactly what I wanted. Tailscale did, right out of the box.

Decision

Run a Tailscale subnet router in a dedicated Proxmox LXC — not in Kubernetes — advertising 192.168.10.0/24 into a private tailnet. Everything about it is declared in Terraform: the container, the tailnet ACL policy, split DNS, and the bootstrap auth key.

This is a deliberate exception to ADR 001’s “Git is the only way in.” The runbook says so explicitly: nothing in this path is managed by ArgoCD, and that is intentional.

The reason is dependency direction. Remote access is what I need most when the cluster is broken — and a tailnet that runs as a Kubernetes workload is unreachable in exactly the scenario it exists for. Putting it in an LXC that boots first (startup order 1) means the recovery path doesn’t depend on the thing being recovered.

It is still infrastructure-as-code; it just answers to Terraform instead of ArgoCD.

Reasoning

Tradeoffs

Outcome

Both ingress paths — the public Cloudflare tunnel and the private tailnet — are drawn in the network layout diagram.

Remote administration now happens over the tailnet, and the public surface stayed exactly three hostnames. The recovery property is the one I care about most: because the router is an LXC that boots before anything else, “the cluster is broken and I’m not home” is now a solvable problem rather than a wait-until-I’m-back problem.