Teissier YannisDeveloper · AI & fullstackLyon · Sept. 2026
Back to the indexProject 02 of 06
02Case study — 2026 → today

Homelab GitOps
a two-node Kubernetes cluster, run like production

K3s across a rented VPS and a machine at home, Argo CD app-of-apps, one Helm chart per app, Jenkins bumping tags, sealed secrets. It deploys everything else on this page.

Role
Everything, design, charts, pipelines, operations
Stack
K3s · Argo CD · Helm · Jenkins · Traefik · WireGuard · Sealed Secrets
Status
In production, at home

The problem

A game server, a web panel, a private registry, a CI, an embeddings service, a couple of websites: side projects pile up, and each one deployed by hand is one more thing that breaks silently. I wanted a single way to put anything in production: declarative, reviewable, reversible with a git revert. And I wanted it on hardware I pay for and understand.

What I built

A K3s cluster on two nodes: a rented VPS that carries the control plane (cordoned, it schedules nothing) and a machine at home that runs every workload, linked by WireGuard. Traffic enters through Cloudflare DNS, hits the VPS on ports 80 and 443, is forwarded through the tunnel to Traefik on the home node, then Ingress, Service, pod. The game servers stay native on the VPS, outside Kubernetes on purpose.

One git repository is the source of truth. Argo CD in app-of-apps mode watches it with prune and self-heal on; every application is a small Helm chart copied from a commented template, never a third-party chart with drifting tags. Jenkins runs in the cluster, builds images in pods, pushes to a private registry, then commits the new tag into the infra repository: that commit is the deployment. Secrets are sealed with a master key kept offline; cert-manager issues TLS; KEDA scales rarely-used services to zero and wakes them on the first request; MinIO holds object storage and nightly pg_dump backups. Ten applications are active, thirteen more are archived with their charts and dumps kept.

fig. 1 — no screenshot, a drawing
Fig. 1 — the cluster · a rented VPS holds the control plane, a home node runs every workload, WireGuard between them01

What I learned

That self-heal is a commitment: nothing can be paused from the cluster, so even "retiring" an app became a repository convention. That host-network ingress, ExternalName services and Argo's resource exclusions each have one silent failure mode, and that writing them down as numbered traps is the only defence. And one honest negative result: I removed Prometheus, Grafana and Loki to give 1.6 GB back to a Minecraft server, and measured that it changed nothing about the game's tick. The bottleneck was elsewhere.

“If it is not in git, it does not exist on the cluster, including the things I would rather have paused by hand.”
Next — 03AltiTrak