The Nightmare Called ‘Click-ops’
I’m currently running a homelab on Proxmox VE with about 12 virtual machines (VMs) and containers. This is where I test everything from Kubernetes clusters and Home Assistant to automation bots.
Initially, using the Proxmox Web UI to select ISOs and configure CPU and RAM for one or two VMs was no big deal. However, things became a nightmare when I needed to quickly spin up a 3-node K3s cluster or frequently reset my lab environment.
Repetitive clicking is not only tedious but also extremely error-prone. Forgetting to enable the QEMU Agent or misconfiguring a VLAN can cost you an extra 15-20 minutes of debugging. To escape this cycle, Infrastructure as Code (IaC) is the only way out for your infrastructure.
Why Choose Terraform Over Scripts or Ansible?
There are many ways to control Proxmox remotely, such as using pvesh, the API, or Ansible modules. However, Terraform stands out due to several key advantages:
- Scripting (Bash/Python): Often lacks state management. If you run a script a second time, it might create a duplicate VM instead of updating the existing one.
- Ansible: Very powerful for software installation (Configuration Management). However, for hardware provisioning, Ansible’s workflow is often not as smooth or clear as Terraform’s.
Terraform manages infrastructure through a State file. It understands exactly what the current system looks like. When you increase RAM from 2GB to 4GB in your code, Terraform will only execute the specific upgrade command instead of tearing everything down and starting over.
Prerequisites
Before you start writing code, you need to prepare the following three elements:
- Proxmox API Token: Never use the root user. Create a dedicated API Token with PVEVMAdmin permissions for security.
- Terraform: Installed on your local machine or a management server.
- Cloud-init Image: This is vital. For Terraform to automatically inject IP addresses and SSH keys without manual intervention, you must create your VMs from a Cloud-init template.
Step 1: Create an API Token
Go to Datacenter > Permissions > API Tokens in the Proxmox UI. After creating a token for a user (e.g., terraform-user), save the Secret ID immediately. Note that it only appears once on the screen.
Step 2: Configure the Terraform Provider
In the Proxmox ecosystem, the Telmate provider remains the most popular choice due to its large community support.
Create a main.tf file with the following provider declaration:
terraform {
required_providers {
proxmox = {
source = "telmate/proxmox"
version = "2.9.14"
}
}
}
provider "proxmox" {
pm_api_url = "https://192.168.1.100:8006/api2/json"
pm_api_token_id = "terraform-user@pve!mytoken"
pm_api_token_secret = "your-very-secret-token"
pm_tls_insecure = true
}
Deploying Your First VM
My advice: never install a VM from a blank ISO when using Terraform. Instead, prepare a VM Template with Cloud-init pre-installed so Terraform can clone it.
Below is a sample code snippet to quickly create an Ubuntu Server VM:
resource "proxmox_vm_qemu" "ubuntu_server" {
count = 1
name = "vm-terraform-${count.index}"
target_node = "pve-node-01"
clone = "ubuntu-22.04-template"
cores = 2
sockets = 1
memory = 2048
agent = 1 # Allow Proxmox to retrieve the IP from the VM
disk {
size = "20G"
type = "scsi"
storage = "local-lvm"
}
network {
model = "virtio"
bridge = "vmbr0"
}
os_type = "cloud-init"
ipconfig0 = "ip=192.168.1.5${count.index}/24,gw=192.168.1.1"
sshkeys = <<EOF
ssh-rsa AAAAB3NzaC1yc2E... your-public-key
EOF
}
The 3-Step Workflow
Once your code is ready, your workflow boils down to three commands:
terraform init: Downloads the necessary plugins.terraform plan: Previews the changes. This is a critical step to ensure you don’t accidentally delete important data.terraform apply: Confirms and executes the deployment.
In practice, using these commands allows me to create a VM in just 45 seconds. Doing it manually usually takes about 5 to 10 minutes per machine.
Hard-Won Lessons Learned
While implementing IaC with Proxmox, I’ve gathered a few lessons to avoid breaking the system:
- Secure your .tfstate file: This file contains your entire infrastructure configuration, including passwords in plain text. Never commit it to a public GitHub repository.
- Leverage Variables: Don’t hardcode IPs or tokens. Separate them into a
variables.tffile for easier management and better security. - Manage VM IDs: Proxmox uses IDs (like 100, 101) for identification. To avoid conflicts with manually created VMs, you should plan a specific ID range for Terraform (e.g., starting from 500).
Conclusion
Combining Terraform and Proxmox isn’t just for enterprise environments. Even for a homelab, this approach helps you develop systemic thinking and excellent reproducibility.
If a server fails, you only need a single command to restore your entire fleet of VMs exactly as they were. Don’t hesitate to try IaC today; the productivity gains will definitely surprise you.
