Skip to content

Repository files navigation

home-ops

Single-node Kubernetes cluster running at home, managed with Flux.

One Talos Linux node, everything in this repository, nothing configured by hand. If the machine dies I want to rebuild it from a clean disk and this Git history, which is the whole reason it is laid out this way.

Status

Live. This is version 3, on Talos, running real workloads: monitoring (kube-prometheus-stack), CNPG-backed Postgres, self-hosted GitHub Actions runners for several private repos, Umami analytics, and Cairn, a UK live-incident lookup service deployed straight from its own repository via Flux.

The history here goes back to January 2021. Version 1 was Kubernetes on a Dell PowerEdge and lived in this repository until electricity prices made a full rack unappealing. Version 2 was k3s on a Dell Optiplex and lives in -DEPRECIATED-k3s-homelab at the v2 tag. Version 3 starts here, on Talos.

Hardware

Node Dell Optiplex 3050 SFF, 4 cores, 8 threads, 32GB
Runs as Talos VM on Hyper-V, external virtual switch
Storage NVMe boot, second SSD for persistent volumes
Planned Minisforum MS-03 class, at which point the Optiplex becomes the spare

One node means no high availability. Upgrades take the cluster down, because there is nowhere to drain to. The docs say so wherever it matters rather than pretending otherwise.

What runs it

Tool Job
Talos Linux The OS. Immutable, no SSH, configured by API
Flux Reconciles this repository into the cluster
Cilium CNI, kube-proxy replacement, and the Gateway API implementation
cert-manager Wildcard certificates over DNS-01
external-dns DNS records from HTTPRoutes
SOPS and age Secrets, encrypted in this repository
Tailscale How I reach the node and the cluster
Renovate Keeps everything current

How it is reached

Nothing is public by default. Services live on *.lab.fobiat.dev and resolve only over Tailscale or the local network. Anything that genuinely needs to be reachable by someone without my tailnet gets its own name and goes through a Cloudflare Tunnel, one service at a time, as a deliberate decision rather than a default.

Tailscale runs as a Talos system extension rather than in the cluster, so the node is reachable before Kubernetes starts. That matters on the day the cluster is the thing that is broken.

Layout

talos/           Machine configuration, encrypted secrets, Image Factory schematic
bootstrap/       Cilium and Flux, installed once before GitOps takes over
kubernetes/
  flux/          Root Kustomization and cluster-wide variables
  components/    Shared Kustomize components
  apps/          Everything else, by namespace
docs/            Runbooks, decision records, and how to rebuild this from nothing

Documentation

Full docs are in docs/. Worth reading first:

  • Bootstrap, bare disk to running cluster
  • Restore, what to do when the disk is gone
  • Decision records, why things are the way they are, including the two choices that go against what most people do

Prior art

This borrows heavily. Worth your time if you are building something similar:

The k8s-at-home organisation was archived in May 2026. The community moved to the Home Operations Discord.

Licence

MIT. Take whatever is useful.

About

Single-node Kubernetes homelab. Talos Linux, Flux, SOPS+age, Tailscale-first.

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages