3 minutes
Rebuilding my homelab (Part 1): goodbye Puppet, hello Ansible!
After moving away from Puppet, I wanted a system that was simpler to manage, easier to extend, and aligned with how modern infrastructure is being handled — especially in smaller environments like a homelab.
The result is a new, GitOps-inspired setup that combines:
Terraform
(OpenTofu) for provisioning VMs on ProxmoxAnsible
for configuration managementGitea
for hosting code and triggering automation via CI/CD workflowsGitea Runners
, both bare metal and in Kubernetes, to apply configuration automaticallyk3s
as my lightweight Kubernetes cluster for services and further automationGarage
as an S3-compatible backend for storing Terraform state
The core idea is this: everything lives in Git. Infrastructure, configuration, secrets (where appropriate), and automation. Whenever I want to change something — provision a new VM, update a service, or tweak a config — I commit the change, push it to Gitea, and let the automation take care of the rest.
It’s lightweight enough for a homelab, but structured enough to be repeatable, maintainable, and close to how production infrastructure is managed in modern DevOps environments.
Here is a little brainstorm session I did to organize all of this:
Why?
When I first set up my homelab, I chose Puppet as my configuration management tool. My goal was to better understand how it works under the hood — not just from the perspective of day-to-day maintenance, but from the ground up.
In my day job, I manage Linux infrastructure at scale, and Puppet plays a central role there. It’s an excellent fit for our environment: we have a large, multi-environment landscape where maintaining state is critical for consistency, scalability, and reliability. Puppet excels at enforcing desired state, which keeps things stable and predictable.
Using Puppet at home helped me think more deeply about how everything ties together: the node communication model, the lifecycle of configurations, and the role of a centralized control server. That experience gave me a much stronger grasp of the full lifecycle — far beyond just running puppet agent -t
.
But now that I’m more familiar with it, I’ve realized that Puppet’s complexity and always-on enforcement model isn’t necessary for a small homelab. I don’t need the same level of rigor or centralized state management — I just need something that can declaratively configure machines, is easy to maintain, and aligns better with modern DevOps tooling.
That’s why I’ve decided to transition to Ansible. It’s lighter, more flexible, and arguably more future-proof. It’s also far more common in the industry today, so getting more hands-on experience with it will be valuable for me professionally.
Of course, there are trade-offs. Ansible is agentless, which means there’s no persistent daemon to enforce state. I’ll need to ensure my roles and playbooks are applied idempotently and regularly — especially to avoid configuration drift when I make manual changes and forget to codify them. But with the right GitOps-style automation, I believe it’ll be a clean and efficient setup going forward.
Let’s get technical in the next part.