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 plan shows exactly what will change before anything happens - the single biggest practical benefit over the web UI, where a misclick just happens.
  • var.proxmox_api_token should 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 version explicitly. Provider releases can introduce breaking changes to resource arguments between versions, and an unpinned apply months later can fail or behave differently than when you wrote it.

⚠️ Risk: tofu apply can 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 apply against new hardware, instead of trying to remember every setting you clicked through originally.
  • Review before change - plan output is a diff you can read before committing to it, which catches mistakes a UI click doesn't.
  • Drift detection - tofu plan also 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.