This repository is the single source of truth for my Kubernetes home lab. Everything from the operating system to application deployments is declared in code and reconciled through GitOps.
| OS | Talos Linux: immutable, API-driven, secure-by-default (lifecycle managed with topf) |
| CNI | Cilium: eBPF networking, kube-proxy replacement, native routing, L2 + BGP announcements, dual-stack; Multus for secondary VLAN interfaces |
| GitOps | ArgoCD: ApplicationSets with a Git directory generator |
| Ingress | Envoy Gateway: two gateways (external, internal) via the Gateway API |
| Storage | Rook Ceph (distributed block) + OpenEBS (local hostpath, ZFS-backed on worker-07) + Garage (S3) |
| Database | CloudNativePG (PostgreSQL) + Dragonfly + ClickHouse |
| Secrets | External Secrets (Infisical + CNPG ClusterSecretStores) + SOPS (age) |
| Auth | Kanidm: standalone OIDC / OAuth2 identity provider (+ LDAP) |
| Certs | cert-manager with Let's Encrypt DNS-01 |
| DNS | external-dns for Cloudflare and UniFi; public ingress through a towonel tunnel |
| Backups | kopiur: PVC snapshots with Kopia to Garage S3; CNPG via the Barman Cloud plugin |
| Monitoring | kube-prometheus-stack (Prometheus / Alertmanager) + Grafana Operator + VictoriaMetrics + VictoriaLogs + Fluent Bit + Tempo + Gatus + ntfy |
| VMs | KubeVirt + CDI |
| GPU | NVIDIA DRA driver on worker-ai-01 (RTX 3090 Ti) |
pitower is the sole cluster: the main workload cluster, self-hosting its own ArgoCD and Kanidm.
| Cluster | Role | Endpoint |
|---|---|---|
pitower |
Main workload cluster (11 nodes) | https://10.20.10.0:6443 (VIP) |
| Node | Role | IP | Hardware |
|---|---|---|---|
| worker-01 | Control Plane | 10.20.10.1 | AMD Ryzen |
| worker-02 | Control Plane | 10.20.10.2 | AMD Ryzen |
| worker-03 | Control Plane | 10.20.10.3 | AMD Ryzen |
| worker-04 | Worker | 10.20.10.4 | Intel (iGPU, dedicated=media-home taint) |
| worker-05 | Worker | 10.20.10.5 | Intel |
| worker-06 | Worker | 10.20.10.6 | Intel |
| worker-07 | Worker | 10.20.10.7 | Dell R630, bare metal (ZFS: fast SSD mirrors, hdd raidz1) |
| worker-08 | Worker | 10.20.10.8 | Raspberry Pi (arm64) |
| worker-09 | Worker | 10.20.10.9 | Raspberry Pi (arm64) |
| worker-10 | Worker | 10.20.10.10 | Raspberry Pi (arm64) |
| worker-ai-01 | Worker | 10.20.10.11 | NVIDIA RTX 3090 Ti (GPU workloads) |
| Device | Purpose |
|---|---|
| UniFi Cloud Gateway Fiber | Router, VLANs, BGP peer for LoadBalancer and pod routes |
| UniFi switching + U7-Pro / U6-Lite | Switching and wireless |
| towonel tunnel | Public ingress (*.wibrow.dev to envoy-external) |
Nodes live on VLAN 20 (10.20.0.0/16), dual-stack with IPv6 from the Init7 delegated prefix. Cilium runs in native routing mode and serves LoadBalancer IPs from 10.20.10.128-255, announced over L2 (ARP) and BGP (ASN 64513 to the gateway's 64512, config in terraform/unifi/frr-bgp.conf); each node's pod CIDR is advertised too, so pods are routable from the LAN. Envoy gateways: envoy-external (10.20.10.239, towonel tunnel) and envoy-internal (10.20.10.238).
| Device | Purpose |
|---|---|
| Synology NAS | Media and bulk data (NFS) |
| Rook Ceph | Distributed block storage (ceph-block, default StorageClass) |
| worker-07 ZFS pools | OpenEBS hostpath (-fast, -media, -runners) and Garage S3 |
| Local SSD | Talos OS + OpenEBS hostpath volumes |
home-ops/
├── .github/workflows/ # CI: checks, ArgoCD diff, Talos diff/apply, Terraform, image builds, docs
├── .justfiles/ # Just task runner recipes
├── 3d-prints/ # Rack mounts and other printed parts
├── ansible/ # Host provisioning
├── docker/ # Container images that can't live in cloudsnacks/containers
├── docs/ # Documentation pages (Markdown, readable on GitHub)
├── iot/ # ESPHome, Home Assistant, Button+ configs
├── kubernetes/
│ ├── apps/ # Application manifests: {cluster}/{category}/{app}
│ ├── argocd/ # ApplicationSets (per cluster)
│ ├── bootstrap/ # ArgoCD bootstrap
│ └── components/ # Reusable kustomize components (kopiur, pvc, cnpg-db-shared)
├── talos/ # Talos configs per cluster (topf-managed, SOPS-encrypted)
├── terraform/ # AWS, Cloudflare, UniFi, etc.
├── workers/status/ # status.wibrow.dev (Cloudflare Worker, outside the cluster on purpose)
├── scripts/ # Helper scripts
├── site/ # Astro site that builds docs/ into swibrow.github.io/home-ops
├── mise.toml # Tooling and env (KUBECONFIG, SOPS key)
└── renovate.json5 # Dependency management
Cluster state is reconciled by ArgoCD. Each cluster has one ApplicationSet using a Git directory generator over kubernetes/apps/{cluster}/*/*: every {category}/{app} directory is discovered automatically, deployed as {cluster}-{category}-{app} into a namespace derived from its category.
Most apps are rendered from the app-template chart (bjw-s-labs) via a helm chart generator. The pitower cluster spans these categories:
kubernetes/apps/pitower/
├── ai/ # agentgateway, Open WebUI, ToolHive, agent-sandbox, ComfyUI, MLflow, SearXNG
├── analytics/ # Rybbit
├── arc/ # GitHub Actions runner controller + runners
├── banking/ # Actual, Firefly III, Ghostfolio, Paperless
├── cert-manager/ # TLS certificate automation
├── database/ # CNPG operator + clusters, Barman Cloud plugin, Dragonfly, ClickHouse
├── dev/ # Forgejo, dev desktop, herdr
├── home-automation/ # Home Assistant, Frigate
├── kopiur-system/ # kopiur operator + Garage repository
├── kube-system/ # Cilium, CoreDNS, Multus, metrics-server
├── kubevirt/ # KubeVirt + CDI
├── media/ # Jellyfin, Immich, Sonarr, Radarr, Prowlarr, autobrr, qBittorrent, SABnzbd
├── monitoring/ # kube-prometheus-stack, VictoriaMetrics/Logs, Grafana, Tempo, Gatus, ntfy, exporters
├── networking/ # Envoy Gateway, external-dns, towonel, Tailscale, netboot
├── openebs/ # Local hostpath provisioner
├── renovate/ # Renovate operator
├── rook-ceph/ # Distributed storage
├── second-brain/ # AFFiNE, CouchDB
├── security/ # Kanidm, External Secrets, CrowdSec, RBAC
├── selfhosted/ # Homepage, Glance, Miniflux, Mealie, n8n, Atuin, Excalidraw, and more
├── system/ # Garage, Reloader, KEDA, Headlamp, Spegel, NVIDIA DRA, Intel device plugins
├── vms/ # KubeVirt virtual machines
├── workflows/ # Argo Workflows + Argo Events
└── workshop/ # Bambuddy
Adding a new application is as simple as creating a directory: ArgoCD discovers and deploys it automatically.
Shout out to the Home Operations community and Uptime Lab.
