Introduction
The Proxmox Terraform provider (bpg/proxmox) allows you to manage Proxmox VE resources — VMs, containers, storage, networks — using Infrastructure as Code. This enables repeatable, version-controlled infrastructure deployments.
Prerequisites
- Proxmox VE 7.x or 8.x cluster
- Terraform 1.x installed
- API token from Proxmox
Creating a Proxmox API Token
In Proxmox UI: Datacenter → Permissions → API Tokens → Add
BASH
# Or via CLI
pveum apitoken add terraform@pve!terraform --privsep 0
pveum aclmod / -user terraform@pve -role AdministratorTerraform Provider Configuration
HCL
# versions.tf
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "~> 0.46"
}
}
}
# provider.tf
provider "proxmox" {
endpoint = "https://proxmox.company.com:8006"
api_token = "terraform@pve!terraform=UUID-TOKEN-HERE"
insecure = false # Set true if self-signed cert
}Creating a VM from Template
HCL
# main.tf
resource "proxmox_virtual_environment_vm" "web_server" {
name = "web-server-01"
node_name = "pve-node1"
vm_id = 201
clone {
vm_id = 9000 # Source template ID
full = true # Full clone
}
cpu {
cores = 4
sockets = 1
type = "x86-64-v2-AES"
}
memory {
dedicated = 4096 # MB
floating = 512 # Ballooning minimum
}
disk {
datastore_id = "local-zfs"
interface = "scsi0"
size = 50 # GB
iothread = true
discard = "on"
}
network_device {
bridge = "vmbr0"
vlan_id = 10
model = "virtio"
}
initialization {
ip_config {
ipv4 {
address = "192.168.10.50/24"
gateway = "192.168.10.1"
}
}
user_account {
username = "admin"
keys = [file("~/.ssh/id_rsa.pub")]
}
dns {
servers = ["8.8.8.8", "8.8.4.4"]
}
}
started = true
}Creating Multiple VMs with count
HCL
variable "web_server_count" {
default = 3
}
resource "proxmox_virtual_environment_vm" "web_cluster" {
count = var.web_server_count
name = "web-${count.index + 1}"
node_name = "pve-node${(count.index % 3) + 1}" # Distribute across 3 nodes
vm_id = 201 + count.index
clone {
vm_id = 9000
full = true
}
cpu {
cores = 2
}
memory {
dedicated = 2048
}
initialization {
ip_config {
ipv4 {
address = "192.168.10.${50 + count.index}/24"
gateway = "192.168.10.1"
}
}
}
}
output "vm_ips" {
value = [for vm in proxmox_virtual_environment_vm.web_cluster :
vm.initialization[0].ip_config[0].ipv4[0].address]
}LXC Container with Terraform
HCL
resource "proxmox_virtual_environment_container" "app_container" {
description = "Application container"
node_name = "pve-node1"
initialization {
hostname = "app-container-01"
ip_config {
ipv4 {
address = "192.168.10.100/24"
gateway = "192.168.10.1"
}
}
user_account {
keys = [file("~/.ssh/id_rsa.pub")]
password = "SecurePassword123"
}
}
network_interface {
name = "eth0"
bridge = "vmbr0"
}
disk {
datastore_id = "local-zfs"
size = 20
}
cpu {
cores = 2
}
memory {
dedicated = 1024
swap = 512
}
operating_system {
template_file_id = "local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst"
type = "ubuntu"
}
started = true
unprivileged = true
}Remote State and Workspaces
HCL
# backend.tf - Store state in S3 or HTTP backend
terraform {
backend "s3" {
bucket = "terraform-state"
key = "proxmox/production/terraform.tfstate"
region = "us-east-1"
}
}BASH
# Initialize and apply
terraform init
terraform plan -out=tfplan
terraform apply tfplan
# Destroy specific resource
terraform destroy -target=proxmox_virtual_environment_vm.web_server
# Import existing VM
terraform import proxmox_virtual_environment_vm.existing_vm pve-node1/qemu/200