No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-22 17:36:22 +02:00
.gitignore Initial setup 2026-08-22 17:36:22 +02:00
.terraform.lock.hcl Initial setup 2026-08-22 17:36:22 +02:00
CLAUDE.md Initial setup 2026-08-22 17:36:22 +02:00
locals.tf Initial setup 2026-08-22 17:36:22 +02:00
main.tf Initial setup 2026-08-22 17:36:22 +02:00
outputs.tf Initial setup 2026-08-22 17:36:22 +02:00
providers.tf Initial setup 2026-08-22 17:36:22 +02:00
README.md Initial setup 2026-08-22 17:36:22 +02:00
terraform.tfvars.example Initial setup 2026-08-22 17:36:22 +02:00
variables.tf Initial setup 2026-08-22 17:36:22 +02:00
versions.tf Initial setup 2026-08-22 17:36:22 +02:00

proxmox-terraform

Declarative, reproducible management of Proxmox VE virtual machines using OpenTofu and the bpg/proxmox provider.

Requirements

  • OpenTofu >= 1.8.0
  • Proxmox provider bpg/proxmox ~> 0.111.0 (pinned in versions.tf)
  • A Proxmox VE cluster/node reachable over the API
  • An API token with permissions to manage VMs, storage, and download files on the target node

Install OpenTofu: https://opentofu.org/docs/intro/install/

Project layout

.
├── versions.tf                 # OpenTofu + provider version pins
├── providers.tf                # Proxmox provider configuration
├── variables.tf                # Input variables, including the `vms` map
├── locals.tf                   # Derived values
├── main.tf                     # Cloud image downloads + VM resources
├── outputs.tf                  # VM IDs, names, nodes, IPs
├── terraform.tfvars.example    # Example variable values (no secrets)
└── .gitignore

VMs are defined data-driven via the vms map variable and created with for_each, so adding a VM does not require copying resource blocks. A modules/vm module is not present; introduce one only if VM patterns diverge enough to need a reusable interface.

Authentication

Credentials are never hard-coded. Provide them via environment variables (preferred) or terraform.tfvars (never committed):

export PROXMOX_VE_ENDPOINT="https://proxmox.example.com:8006"
export PROXMOX_VE_API_TOKEN="user@realm!tokenid=uuid"

If you set proxmox_endpoint / proxmox_api_token in terraform.tfvars instead, keep that file local only — it is excluded via .gitignore.

Usage

# Copy and edit the example variables
cp terraform.tfvars.example terraform.tfvars

# Format, initialize, and validate
tofu fmt -recursive
tofu init
tofu validate

# Review changes before applying
tofu plan

# Apply only after reviewing the plan
tofu apply

Adding a VM

Add an entry to the vms map (in terraform.tfvars or a *.auto.tfvars file), then plan and apply:

vms = {
  web01 = {
    name      = "web01"
    cores     = 2
    memory_mb = 4096
    disk_gb   = 32
    image_url = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
    ip_config = "10.0.0.20/24"
    gateway   = "10.0.0.1"
    tags      = ["web"]
  }
}

Keep map keys stable once a VM exists — renaming a key causes OpenTofu to destroy and recreate that VM.

Destroying a VM or the whole environment

Review the plan carefully; never use -auto-approve for destructive changes.

tofu plan -destroy
tofu destroy

Assumptions to verify for your environment

  • Node: proxmox_node must match an existing Proxmox node name.
  • Storage: storage_pool must be a datastore on that node capable of holding VM disks and imported images (e.g. local-lvm, a ZFS pool, or similar).
  • Network bridge: network_bridge must be an existing bridge (e.g. vmbr0); VLAN tagging is optional per VM via vlan_id.
  • Cloud images: image_url should point at a cloud-init-enabled qcow2/raw image (e.g. official Ubuntu/Debian cloud images).
  • SSH keys: ssh_public_key must be a public key; private keys are never used here.

None of these are assumed by default — they are required variables or per-VM fields, so review terraform.tfvars.example and set real values for your cluster.

State

State is local by default (no backend block). If more than one person or CI will run this project, configure a remote backend before continuing. Never commit *.tfstate, *.tfstate.*, or .terraform/.