Homelab
Tailscale High Availability
Enabling High Availability for Tailscale Kubernetes Subnet Router
Overview
Enabling high availability1 for the Tailscale subnet router. With multiple replicas, if one pod fails (TPM issues, node failure, etc.), another takes over automatically within 15 seconds.
| Tip: | Having trouble? See v0.9.2 for what your setup should look like after completing this article. |
Before You Begin
Prerequisites
- Tailscale ACL and Subnet Routes completed (3 nodes routed)
Configure Connector for HA
Pin subnet router replicas to control plane nodes with anti-affinity to ensure one per node.
ProxyClass
k8s/core/tailscale/connector/proxyclass.yaml:
---
apiVersion: tailscale.com/v1alpha1
kind: ProxyClass
metadata:
name: control-plane
spec:
statefulSet:
pod:
nodeSelector:
node-role.kubernetes.io/control-plane: ""
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
tailscale.com/parent-resource: homelab-subnet
topologyKey: kubernetes.io/hostname Connector
Update the Connector2 to use multiple replicas.
k8s/core/tailscale/connector/connector.yaml:
---
apiVersion: tailscale.com/v1alpha1
kind: Connector
metadata:
name: homelab-subnet
spec:
replicas: 3
proxyClass: control-plane
hostnamePrefix: homelab-subnet
subnetRouter:
advertiseRoutes:
- "192.168.1.30/32" # Control plane node
- "192.168.1.31/32" # Control plane node
- "192.168.1.32/32" # Control plane node
- "192.168.1.40/29" # MetalLB pool .40-.47
- "192.168.1.48/28" # MetalLB pool .48-.63
- "192.168.1.64/28" # MetalLB pool .64-.79 Changes from single replica:
| Field | Before | After |
|---|---|---|
replicas | (default 1) | 3 |
proxyClass | (not set) | control-plane |
hostname | homelab-subnet | removed |
hostnamePrefix | (not set) | homelab-subnet |
Apply Changes
Commit Changes
git add k8s/core/tailscale/connector/
git commit -m "feat(tailscale): enable HA with 3 replicas on control plane nodes"
git push Reconcile Flux
flux reconcile source git flux-system
flux reconcile kustomization sync Verify Configuration
Pod Distribution
Check pods are distributed across nodes:
kubectl get pods -n tailscale -l tailscale.com/parent-resource=homelab-subnet -o wide Should show 3 pods, one per control plane node.
| Tip: | If a pod CrashLoops with TPM_RC_INTEGRITY error, delete its state secret: kubectl delete secret -n tailscale ts-homelab-subnet-<replica>-<id> then delete the pod. Other replicas maintain access. |
Tailscale Admin
Check Tailscale Machines:
- Should see
homelab-subnet-0,homelab-subnet-1,homelab-subnet-2 - All should show subnets under "Approved"
- Delete the old
homelab-subnetdevice (will show offline)
Test Connectivity
ping 192.168.1.30 Next Steps
For emergency cluster access when all subnet router replicas are down, set up a bastion host.
See: Tailscale Mac Bastion Host
Resources
Footnotes
Tailscale, "Set up high availability," tailscale.com. Accessed: Dec. 21, 2025. [Online]. Available: https://tailscale.com/kb/1115/high-availability ↩
Tailscale, "Deploy exit nodes and subnet routers on Kubernetes," tailscale.com. Accessed: Dec. 21, 2025. [Online]. Available: https://tailscale.com/kb/1441/kubernetes-operator-connector ↩