Infrastructure as Code
Using Terraform or OpenTofu to provision Proxmox VMs declaratively instead of clicking through the web UI, and what it costs you to maintain.
Everything so far has been created by clicking through the Proxmox web UI or running one-off shell commands. That works fine until you need to rebuild a node, remember exactly how a VM was configured, or replicate a setup across a cluster. Infrastructure as code (IaC) is the practice of describing that configuration as files instead.
Terraform and OpenTofu
Terraform (HashiCorp) is the tool most people mean by "IaC" in practice. OpenTofu is a community-governed fork created after HashiCorp changed Terraform's license in 2023 - functionally near- identical, a drop-in replacement using the same syntax (HCL). For a new homelab setup, OpenTofu is the more future-proof pick precisely because it's open source with no license risk; either works fine for what's described here. Check current licensing terms before choosing, since this space has shifted before and could again.
Both use the Proxmox provider
(the bpg/proxmox provider is the actively maintained community
option; an older Telmate provider also exists but sees less
development) to talk to Proxmox's API and create VMs, containers, and
other resources from a declarative file.
A minimal example
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "0.66.0"
}
}
}
provider "proxmox" {
endpoint = "https://proxmox.home.lan:8006/"
api_token = var.proxmox_api_token
insecure = true
}
resource "proxmox_virtual_environment_vm" "test_vm" {
name = "iac-test"
node_name = "node1"
cpu {
cores = 2
}
memory {
dedicated = 2048
}
disk {
datastore_id = "local-lvm"
size = 20
}
}
tofu init
tofu plan
tofu apply
tofu planshows exactly what will change before anything happens - the single biggest practical benefit over the web UI, where a misclick just happens.var.proxmox_api_tokenshould come from a variable, not a literal string in the file - see Secrets Management for why and how to keep it out of version control.- Pin the provider
versionexplicitly. Provider releases can introduce breaking changes to resource arguments between versions, and an unpinnedapplymonths later can fail or behave differently than when you wrote it.
⚠️ Risk:
tofu applycan destroy and recreate resources if you change an argument that requires replacement (some disk or network changes do). Always read the plan output's Add/Change/Destroy summary before confirming - it's not a formality.
Why this matters even running solo
The case for IaC isn't really about scale - it's about the same person a year from now:
- Rebuildability - a dead node or corrupted config becomes
tofu applyagainst new hardware, instead of trying to remember every setting you clicked through originally. - Review before change -
planoutput is a diff you can read before committing to it, which catches mistakes a UI click doesn't. - Drift detection -
tofu planalso tells you when the real infrastructure no longer matches the file (someone, i.e. you, changed something by hand in the UI), which is otherwise invisible until it breaks something.
The honest cost
This is a genuine second discipline to maintain: HCL syntax to learn,
provider version upgrades to track, state files
(terraform.tfstate) that need their own backup and are awkward if
multiple people edit infrastructure at once. For a homelab with a
handful of VMs that rarely change, hand-clicking them in the Proxmox
UI once is legitimately less total effort than writing and maintaining
Terraform for them. IaC earns its keep when you rebuild often, run
enough VMs that consistency matters, or want the audit trail - not as
a default for every VM you'll ever create.
Next: Configuration Management.