My homelab runs Kubernetes on Talos Linux. Flux keeps the cluster in sync with this repository.
| Component | Purpose |
|---|---|
| Cilium | Pod networking and load balancing |
| Envoy Gateway | HTTP routing through the Kubernetes Gateway API |
| Cloudflared | Cloudflare Tunnel for external access |
| external-dns | Automatic DNS records |
| cert-manager | TLS certificates |
| External Secrets | Kubernetes secrets from 1Password Connect |
| SOPS | Encryption for secrets stored in Git |
| Spegel | Container image sharing between nodes |
| Prometheus, Grafana and Loki | Metrics, dashboards and logs |
| Actions Runner Controller | Self-hosted GitHub Actions runners |
Most other k8s homelab clusters use node-local storage like Rook/Ceph for persistent volumes. I have recently torn that out to save cluster resources, and now use iSCSI via 10GBe network on a Synology NAS.
Flux applies the configuration under kubernetes/apps, grouped by namespace. Each app's ks.yaml points to its manifests, usually a HelmRelease and supporting resources. Dependencies control deployment order.
Renovate opens pull requests for dependency updates. Flux applies merged changes to the cluster.
kubernetes/apps/networking/tailscale-router runs a standalone Tailscale subnet/exit router against https://hs.mcgrath.nz. Headscale 0.29.3 does not provide the OAuth API needed by the native Kubernetes operator, so the previous operator and Connector have been removed.
- Router:
ts-pod-cidrs.tailnet.hs.mcgrath.nz(100.64.0.2), taggedtag:homelab-router. - Advertised subnets:
10.0.16.0/24,10.0.10.0/24,10.244.0.0/16,172.16.10.0/24; also advertises IPv4/IPv6 exit-node routes. Headscale auto-approves these through policy in the separatejumperrepository. - Kubernetes API: use the existing authenticated kubeconfig endpoint
https://10.0.16.132:6443over the subnet route. The old operator-specific API proxy is gone. - Enrollment: 1Password vault
Kubernetes, itemheadscale-router, concealed fieldauth_key. External Secrets producesnetworking/tailscale-router-auth; no enrollment key is stored in Git. - Identity:
networking/tailscale-router-stateholds Tailscale state across pod replacements. Keep it when restarting or updating the app. The service account can only get/update/patch this named Secret. - Talos: automatic firewall selection uses nftables; legacy iptables is unavailable. Forwarding is enabled inside the pod network namespace, without host networking.
Linux clients need tailscale set --accept-routes=true. To use the home connection as an exit node, select ts-pod-cidrs in the client or run tailscale set --exit-node=ts-pod-cidrs; clear it with tailscale set --exit-node=.
The reusable tagged enrollment key expires 2026-12-19 05:27:55 UTC. Its expiry does not disconnect the already-enrolled router: TS_AUTH_ONCE=true reuses the persisted identity. Before fresh enrollment or recovery without that state, create a replacement with headscale preauthkeys create --tags tag:homelab-router --reusable --expiration 2160h on Jumper and update auth_key, headscale_key_id, and expires_at in the vault item. Refresh tailscale-router-auth through External Secrets before starting a new identity. Do not paste keys into Git or command-line arguments.
Operational checks:
flux reconcile kustomization tailscale-router --with-source
kubectl -n networking get helmrelease tailscale-router
kubectl -n networking exec deployment/tailscale-router -- tailscale statusVerified on 2026-09-20 from an independent Azure tailnet client: Kubernetes API TLS validation and expected unauthenticated HTTP 401, pod metrics HTTP 200, internal load-balancer HTTP 301, ICMP to 10.0.10.1, and IPv4 exit traffic through home IP 101.98.238.192. Router identity survived pod replacement and Flux reapplication. Temporary verification resources were removed.
talos/ # Node configuration and OS image templates
bootstrap/ # Cluster bootstrap configuration
kubernetes/
apps/ # Applications
flux/ # Flux configuration, sources and cluster variables
components/ # Shared Kustomize components
.taskfiles/ # Operational tasks
Inspired by the Home Operations community and flux-cluster-template. KubeSearch has examples from other homelabs.