VM Lifecycle Management¶
This guide covers the full VM lifecycle — from creation through day-2 updates to destruction — focusing on Proxmox-specific behaviors that affect how Terraform manages your VMs.
Creating a VM¶
A typical VM starts with a cloud image download and a proxmox_virtual_environment_vm resource:
resource "proxmox_virtual_environment_download_file" "ubuntu_cloud_image" {
content_type = "iso"
datastore_id = "local"
node_name = var.virtual_environment_node_name
url = "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
}
resource "proxmox_virtual_environment_vm" "example" {
name = "example-vm"
node_name = var.virtual_environment_node_name
description = "Managed by Terraform"
machine = "q35"
bios = "ovmf"
started = true
# Always set stop_on_destroy when started = true,
# otherwise Terraform will attempt a graceful ACPI shutdown
# that may hang if the guest agent is not installed.
stop_on_destroy = true
cpu {
cores = 2
}
memory {
dedicated = 2048
}
efi_disk {
datastore_id = var.datastore_id
type = "4m"
}
disk {
datastore_id = var.datastore_id
file_id = proxmox_virtual_environment_download_file.ubuntu_cloud_image.id
interface = "virtio0"
iothread = true
discard = "on"
size = 20
}
initialization {
ip_config {
ipv4 {
address = "dhcp"
}
}
}
network_device {
bridge = "vmbr0"
}
}
Key points:
starteddefaults totrue— the VM will boot after creation. Setstarted = falsefor templates.- Templates ignore
started— whentemplate = true, the VM is never started regardless of thestartedvalue. Setstarted = falseexplicitly to avoid confusion. stop_on_destroy = trueis recommended for started VMs — without it, Terraform sends an ACPI shutdown and waits for the guest to power off. If the guest agent is not installed or the guest hangs, the destroy will time out.
Updating a VM¶
Proxmox supports hotplugging some attributes while a VM is running. Other changes require a reboot, and some force full recreation of the VM.
resource "proxmox_virtual_environment_vm" "hotplug_example" {
name = "hotplug-example"
node_name = var.virtual_environment_node_name
started = true
stop_on_destroy = true
# reboot_after_update defaults to true.
# When a non-hotpluggable attribute changes (e.g. cpu.cores),
# Terraform will automatically reboot the VM to apply it.
# Set to false if you prefer to reboot manually.
reboot_after_update = true
cpu {
# Changing cores or sockets requires a reboot.
cores = 4
sockets = 1
}
memory {
# Memory is hotpluggable (increase only) when the VM's hotplug
# setting includes "memory".
dedicated = 4096
}
disk {
datastore_id = var.datastore_id
interface = "virtio0"
iothread = true
discard = "on"
# Disks can only grow. Shrinking produces an error.
size = 40
}
network_device {
bridge = "vmbr0"
}
# Adding a second NIC is hotpluggable.
network_device {
bridge = "vmbr0"
vlan_id = 100
}
}
Hotplug vs reboot vs recreate¶
When reboot_after_update = true (default), Terraform automatically reboots or powers off the VM during update operations when required to apply changes. Set it to false if you prefer to keep the VM online unless you intervene manually.
With reboot_after_update = false, there are two outcomes:
- If the change was applied successfully but the guest still needs a later reboot to fully pick it up, Terraform completes the apply and emits a warning.
- If the change cannot be applied at all without taking the VM offline first, Terraform fails the apply with an error instead of powering the VM off automatically.
| Change | Behavior |
|---|---|
memory.dedicated (increase) |
Hotplug (when VM hotplug includes memory) |
| Adding a network device | Hotplug |
cpu.cores, cpu.sockets |
Requires reboot |
cpu.type |
Requires reboot |
machine, bios |
Requires reboot |
disk.size (increase) |
Applied online when possible; may still require manual reboot later for non-hotpluggable disk setups |
disk.size (decrease) |
Error — disks can only grow |
disk.interface |
Deletes old disk, creates new (data-destructive, not VM recreation) |
template |
false -> true converts in place; true -> false is unsupported |
Info
Tip: Run terraform plan after changing VM attributes. The plan output will indicate whether a change triggers an in-place update or forces replacement.
Destroying a VM¶
Three attributes control what happens when Terraform destroys a VM:
resource "proxmox_virtual_environment_vm" "destroy_example" {
name = "destroy-example"
node_name = var.virtual_environment_node_name
started = true
# When false (default), Terraform sends an ACPI shutdown and waits
# for the guest to power off gracefully. Setting to true force-stops
# the VM immediately, which is safer for started VMs without a
# guest agent.
stop_on_destroy = true
# purge_on_destroy = true (default): Removes backup jobs, replication
# entries, and HA configuration for this VM on destroy.
purge_on_destroy = true
# delete_unreferenced_disks_on_destroy = true (default for vm resource):
# Deletes any disks not tracked by Terraform on destroy.
# The cloned_vm resource defaults to false for safety.
delete_unreferenced_disks_on_destroy = true
cpu {
cores = 2
}
memory {
dedicated = 2048
}
disk {
datastore_id = var.datastore_id
interface = "virtio0"
size = 20
}
network_device {
bridge = "vmbr0"
}
}
| Attribute | Default (vm) |
Default (cloned_vm) |
Effect |
|---|---|---|---|
stop_on_destroy |
false |
false |
false = ACPI shutdown (graceful), true = force stop |
purge_on_destroy |
true |
true |
Remove backup jobs, replication, and HA config |
delete_unreferenced_disks_on_destroy |
true |
false |
Delete disks not tracked by Terraform |
Warning
Warning: The vm resource defaults delete_unreferenced_disks_on_destroy to true, which deletes any disk not explicitly declared in your Terraform config. If you attach disks outside Terraform, set this to false to prevent data loss.
For the cloned_vm resource, see the Clone VM guide and the Choosing Between Clone Resources guide for details on the delete block and inherited device management.
Quick reference¶
| Operation | What to set |
|---|---|
| Create a running VM | started = true, stop_on_destroy = true |
| Create a template | template = true, started = false |
| Resize disk up | Increase disk.size — applied online |
| Add memory (hot) | Increase memory.dedicated (requires hotplug to include memory) |
| Change CPU cores | Change cpu.cores — auto-reboots by default |
| Prevent auto-reboot | reboot_after_update = false |
| Force-stop on destroy | stop_on_destroy = true |
| Keep unmanaged disks | delete_unreferenced_disks_on_destroy = false |
Full example is available in the examples/guides/vm-lifecycle directory.