The homelab started as a set of shell commands I ran once and then forgot. It worked, until the day I needed to rebuild a container and could not remember which volume held the database.
That is the moment infrastructure as code stops being a hobby and starts being a recovery plan.
What I moved into Terraform
Not everything. Terraform is a poor fit for things that change every day. I drew a line:
- In Terraform: Proxmox virtual machines, DNS records, object storage buckets, and firewall rules.
- Not in Terraform: application containers, their config files, and anything managed by Docker Compose.
The split is deliberate. Terraform owns the things that are expensive to recreate. Docker Compose owns the things that change with every application release.
The state file is the system
The first useful habit was putting state in remote storage with locking. A local terraform.tfstate on a laptop is a single point of failure, and it is invisible until two people apply at once.
The second habit was reading the plan. Every apply starts with terraform plan -out=tfplan, and I read the diff before applying it. Twice, the plan showed a resource being replaced rather than updated. Both times, that would have been an outage.
Drift is normal
Something will always be changed outside Terraform. A quick fix in the Proxmox UI, a DNS record added during an incident. The goal is not zero drift; the goal is to notice it.
A weekly plan run in CI reports drift without applying anything. If the diff is intentional, I import or codify it. If it is not, I revert it. Either way, the state file and reality converge on purpose.
terraform plan -detailed-exitcode -out=tfplan
# 0 = no changes, 1 = error, 2 = changes presentWhat I would tell someone starting
Start with one resource. A DNS record is enough. Get comfortable with plan, apply, and state before you put a whole network in there. Then write the runbook for the day the state is lost — because that runbook is the actual disaster recovery plan.