Overview
Most of the posts in this series so far have been “here’s how I built X.” This one’s different. It’s about something I built, used for a while, and then mostly walked away from: a Kubernetes cluster running Talos .
This isn’t a “Kubernetes is bad” post. It’s a “here’s what it was actually like to run it at home, and why I ended up somewhere simpler” post. The short version: I moved from a Talos-based Kubernetes cluster to a single Proxmox host running a mix of LXC containers and VMs, with Dokploy and Docker Compose handling application deployment.
Why Kubernetes, Originally
Talos was appealing for reasons that probably sound familiar to anyone who’s gone down this path. It’s immutable, API-driven, and gives you the same primitives you’d use professionally. For someone who spends their day job around deployment pipelines and infrastructure, running “the real thing” at home felt like both good practice and a genuinely interesting system to operate.
And for a while, it worked. Services ran as Deployments, configuration lived as YAML, and the whole thing felt appropriately “serious.”
The Breaking Point
The cracks weren’t dramatic. Nothing caught fire. But there was one moment that made the overall trade-off impossible to ignore.
Talos manages itself through a talosconfig, and the cluster through a kubeconfig, both containing certificates and secrets needed to actually talk to the cluster. Mine lived on my personal PC at home. One day I left with just my laptop, wanted to check on something or make a small change, and simply couldn’t. The files I needed to manage my own infrastructure weren’t with me, and they weren’t the kind of thing I wanted to casually copy onto a laptop just in case.
That’s the moment the trade-off became concrete. For a professional setup, this is a solved problem: proper secret management, bastion hosts, CI pipelines that hold the credentials so you don’t have to. For a homelab, I’d built something where keeping it secure meant keeping it tethered to one machine, and keeping it accessible meant compromising on that security. Neither option worked, and the rest of the overhead I’d mostly been tolerating suddenly felt like it wasn’t buying me anything in return.
Where Else the Friction Showed Up
Once that crack appeared, the other sources of overhead were easier to see for what they were. Not the cause of the move, but reasons it didn’t feel like a loss.
Resource overhead relative to workload size. Kubernetes’ control plane, combined with Talos’s own footprint, consumes a non-trivial chunk of resources before a single application workload starts. On a single mini PC, that’s overhead competing directly with the things I actually wanted to run: Jellyfin , the *arr stack, Home Assistant , and so on.
YAML-per-everything. Even simple services ended up needing a Deployment, a Service, sometimes an Ingress, a PVC, and associated config, for things that, conceptually, are “run this container, give it a volume, expose a port.” The ceremony was the same regardless of whether the service was complex or trivial.
Debugging overhead during outages. When something went wrong, the question was rarely just “is the container running?” It was “is the pod scheduled, is the node ready, is the CNI happy, is the PVC bound, is the ingress controller routing correctly?” Each of those is a reasonable thing for Kubernetes to manage, but each is also another layer to check when troubleshooting late at night.
The gap between “homelab” and “production.” A lot of what makes Kubernetes valuable (rolling updates across many nodes, horizontal scaling, scheduling workloads across a fleet) assumes a fleet. A single-node, or small multi-node, homelab doesn’t really have the problem Kubernetes was designed to solve, which means you’re paying the complexity cost without getting most of the benefit.
None of this means Talos or Kubernetes are bad. They’re excellent at what they’re built for. It just became clear that what they’re built for and what I actually needed had drifted apart.
What Changed: Proxmox + Dokploy + Compose
The new setup runs on a single Proxmox host (an AOOSTAR GEM12 Max mini PC), with workloads split between LXC containers for lightweight services and full VMs for anything requiring kernel isolation or complex hardware passthrough, like Home Assistant with its USB Zigbee dongle. Application deployment is orchestrated by Dokploy, which offers a clean UI for managing Compose stacks and automated database provisioning (Postgres , Redis , etc.) without the heavy overhead of a full PaaS.
The shift in mental model is the biggest change. Instead of “describe the desired state and let the scheduler figure it out,” it’s closer to “here’s a compose file, here’s where it runs, go.” For a homelab where I already know exactly where everything lives, that’s not a downgrade. It’s just matching the tool to the actual problem.
A rough before/after for a single service looks something like this. Where Kubernetes needed a Deployment, a Service, and often a PVC and Ingress spread across multiple YAML files, the same service under Compose is one block:
services:
jellyfin:
image: jellyfin/jellyfin:latest
volumes:
- ./config:/config
- /mnt/media:/media
ports:
- "8096:8096"
restart: unless-stopped
Routing and TLS are handled by Caddy , sitting in front of everything, with Cloudflare Tunnel providing external access without exposing any ports directly. Inside Dokploy, Traefik handles internal routing for containerized stacks. CoreDNS handles internal name resolution, and Netbird provides mesh VPN access across devices. The supporting infrastructure tier didn’t disappear, it just got simpler and more directly observable.
What I Gained
Faster iteration. Changing a service is editing a compose file and redeploying. No waiting on a scheduler, no reconciliation loop to watch.
Lower baseline overhead. More of the host’s resources go to actual workloads rather than control-plane processes.
Easier debugging. “Is the container running, and what does docker logs say” covers the overwhelming majority of issues. The troubleshooting surface area shrank significantly.
A setup that matches its scale. One host, one mental model, no abstractions standing in for a multi-node fleet that doesn’t exist.
What I Gave Up
To be fair to Kubernetes: some things genuinely got less automatic. Rolling updates, self-healing restarts across nodes, and the broader ecosystem of operators and CRDs are either gone or replaced by simpler, more manual equivalents. For a homelab, that trade has been worth it, but it’s a real trade, not a strictly-better-in-every-way swap.
Lessons Learned
If I were advising someone starting a homelab today, I don’t think “skip Kubernetes” is the universal lesson. Running Talos taught me a lot, and that’s valuable on its own. The actual lesson is closer to: periodically check whether your infrastructure still matches your actual workload, rather than the workload you imagined having, or the setup that felt most “correct” when you built it.
A single-node homelab running a dozen self-hosted apps and a Kubernetes cluster designed for fleets of nodes are solving different problems. It’s fine to run the latter for the experience, just worth being honest about which problem you’re actually trying to solve, and revisiting that periodically.
Conclusion
The current Proxmox + Dokploy + Compose setup isn’t more “advanced” than the Talos cluster it replaced. In some ways it’s simpler by design, and that’s the point. Everything from this series so far, the Hugo blog pipeline , the NixOS/Colmena deployments , and the monorepo sync , runs on top of this simplified foundation. Sometimes the most useful infrastructure change is the one that takes things away.