Automating Ubuntu VM Deployment on Proxmox VE with Terraform + Cloud-Init

In modern infrastructure management, repeatability and automation are key. Manually creating VMs through a GUI works for quick tests, but it doesn’t scale, and it’s error-prone.
In this post, I’ll share how I automated the creation of multiple Ubuntu 22.04 VMs on Proxmox VE 8.4 using Terraform and cloud-init — complete with static IP addresses, and configured for password authentication without SSH keys.
🛠 Why Terraform with Proxmox?
Terraform lets you define infrastructure as code (IaC).
You can version control your setup
Spin up or destroy VMs in seconds
Enforce consistency across environments
Proxmox has an API, and the Telmate Terraform provider makes it possible to drive VM creation directly from your .tf
files.
🗂 Folder Structure
.
├── main.tf # The VM resource definitions
├── variables.tf # All configuration variables
├── versions.tf # Terraform & provider versions
├── terraform.tfvars # My actual values for variables
🔧 What I Built
I created a Terraform configuration that:
Connects to Proxmox via API token authentication
Clones a cloud-init–enabled Ubuntu 22.04 template
Deploys three VMs with:
Static IP addresses
Cloud-init user accounts
Password authentication instead of SSH keys
Outputs VM names and IDs automatically after provisioning
Pre-requisite:
Proxmox VE-8.4 installed
Terraform installed on Local machine
Properly configured Network on Proxmox
Task List for automation:
Ubuntu VM template ready from Proxmox CLI
Proxmox User creation and api token configuration
Writing the terraform artifact
Ubuntu VM template ready from Proxmox CLI
#Run on the Proxmox node (adjust storage if not local-lvm):
# 1) Get Ubuntu 22.04 cloud image
cd /var/lib/vz/template/iso wget -O jammy.img https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
# 2) Create a VM shell (ID 9000) for the template
qm create 9000 --name ubuntu-22.04-ci-template --memory 2048 --cores 2 \
--net0 virtio,bridge=vmbr0
# 3) Import the cloud image as a disk on your storage (edit storage if needed)
qm importdisk 9000 /var/lib/vz/template/iso/jammy.img local-lvm
# 4) Attach disk + cloud-init, set boot order
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0
qm set 9000 --ide2 local-lvm:cloudinit
qm set 9000 --boot c --bootdisk scsi0
qm set 9000 --serial0 socket --vga serial0
# (optional) grow disk to match your TF var (e.g., 25G)
qm resize 9000 scsi0 25G
# 5) Enable QEMU guest agent (useful for IP reporting)
qm set 9000 --agent enabled=1
# 6) Convert to template
qm template 9000
Proxmox User creation and api token configuration
In the Proxmox web UI:
Go to Datacenter → Permissions → Users → Add.
User ID: terraform
Realm: pve (or pam if you want system authentication)
Password: (set any; not used for token auth)
Click Add.
# 1) make sure the user exists in pve realm
pveum user add terraform@pve || true
# 2) (optional) give the user a password you’ll remember
pveum passwd terraform@pve
# 3) create a new API token WITH privilege separation
pveum user token add terraform@pve tf --privsep 1
# -> copy the returned "value" (token secret). Keep it safe.
Check Your API and user from Postman
curl -k -H "Authorization: PVEAPIToken=terraform@pve!tf=your api token" \
https://192.168.31.43:8006/api2/json/access/users
Github Link for Terraform Code
rm -rf .terraform .terraform.lock.hcl # If previous step was hold
terraform init -upgrade
terraform plan
terraform apply
Subscribe to my newsletter
Read articles from Md Rasel directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Md Rasel
Md Rasel
I’m Md. Rasel, a DevOps Lead at Synesis IT PLC with over a decade of experience in DevOps, Cloud Infrastructure, and Virtualization. My work blends automation, scalability, and reliability to help organizations build resilient, high-performing systems. I specialize in Kubernetes, Docker, Terraform, Jenkins, AWS, OCI, and Proxmox VE, along with CI/CD pipeline design, cloud-native application deployment, and infrastructure automation. My experience spans managing multi-tier applications, orchestrating containerized workloads, implementing secure DevSecOps practices, and optimizing cloud resources for cost and performance. Beyond hands-on engineering, I’m passionate about mentoring and training, having conducted technical workshops on topics like Kubernetes, network automation, monitoring, and cloud strategies at universities and industry events. When I’m not solving infrastructure challenges, I share insights on DevOps best practices, automation strategies, cloud-native technologies, and real-world troubleshooting—making complex tech approachable and actionable. Specialties: CI/CD Pipelines (Jenkins, GitLab CI) Kubernetes & Container Orchestration Infrastructure as Code (Terraform, Ansible) Cloud Platforms (AWS, Oracle Cloud, Azure) Monitoring & Observability (Prometheus, Grafana, ELK, Zabbix) DevSecOps & Security Automation 💡 Let’s connect—I’m always open to discussions about scalable architectures, DevOps automation, and cloud-native innovations.