Proxmox · Templates

Proxmox VM Templates and Cloning

How to turn a cloud-init-ready VM into a reusable Proxmox template, then clone it in seconds instead of reinstalling an operating system every time the homelab needs a new box.

Quick idea: A Proxmox template is a locked, un-startable VM that exists purely to be cloned. Build it once with cloud-init baked in, and every new VM after that is a clone command instead of an ISO install.
Template

A read-only base VM. It cannot be started, only cloned.

Full Clone

An independent copy of every disk. Costs full disk space, owes nothing to the template.

Linked Clone

A copy-on-write clone that only stores changed blocks, but stays dependent on the template.

What Are Templates and Clones?

A Proxmox VM template is a normal virtual machine that has been converted into a locked, deploy-only state. Once converted, it can no longer be booted, edited through the console, or run in any way. Its only purpose is to be the source for the Clone operation.

Think of a template as a rubber stamp rather than a document. You do not write on the stamp itself, you press it to make new copies, and every copy starts out identical to what the stamp says. Cloning a template is that stamping action: a new VM ID, a new set of disks, and (with cloud-init) a fresh hostname, IP address, and SSH key on first boot.

Proxmox supports two clone types. A full clone copies every disk block to new storage, ending up completely independent of the source. A linked clone uses copy-on-write: the clone’s disk starts empty and only stores the blocks that change after cloning, reading everything else straight from the template. That makes linked clones fast to create and light on storage, but they cannot run if the underlying template is ever deleted.

Key rule: Linked clones require storage that supports copy-on-write: qcow2 or raw files on local/NFS storage, or LVM-thin, ZFS, RBD (Ceph). LVM (thick) and iSCSI do not support linked clones, only full clones will work on those.

Full Clone or Linked Clone?

The choice is a trade-off between independence and speed, not a universal “better” option.

Use Full Clone

Production VMs, anything you might migrate to another node, or VMs that must survive the template being deleted.

Use Linked Clone

Disposable lab VMs, quick throwaway test boxes, anything you rebuild from scratch more often than you keep long-term.

Storage Cost

A full clone of a 20 GB template costs 20 GB. A linked clone costs only the blocks that change after boot.

Why This Matters for a Homelab

A homelab gets rebuilt constantly: a new domain controller for a lab scenario, a throwaway box to test a script against, a fresh VM because the last one got misconfigured beyond fixing. Reinstalling an OS from ISO every time is the single biggest time sink in a lab that otherwise runs itself. A cloud-init-ready template turns that fifteen-minute install-and-configure cycle into a clone command that finishes before the console even connects.

It also makes lab work more reproducible. If a test needs a clean Ubuntu box with a known baseline, cloning the same template every time removes the “what did I change last time and forget about” problem that creeps in when VMs get reused and patched ad hoc.

Building a Cloud-Init Template

The fastest path is starting from a cloud provider’s cloud image (a minimal, cloud-init-enabled disk image) rather than installing from an ISO by hand. This example uses an Ubuntu cloud image; most major distributions publish an equivalent.

# Create the VM shell — no disk yet, VirtIO SCSI controller
# for the cloud-init image's expected driver
qm create 9000 --name ubuntu-2404-template --memory 2048 \
  --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci

# Import the downloaded cloud image straight onto scsi0
qm set 9000 --scsi0 local-lvm:0,import-from=/var/lib/vz/template/iso/noble-server-cloudimg-amd64.img

# Attach a cloud-init drive — this is where Proxmox injects
# hostname, SSH keys, and network config on first boot
qm set 9000 --ide2 local-lvm:cloudinit

# Boot from the imported disk
qm set 9000 --boot order=scsi0

# Cloud images expect a serial console, not a graphical one
qm set 9000 --serial0 socket --vga serial0

# Grow the disk before converting to a template — clones
# inherit whatever size the template has at conversion time
qm resize 9000 scsi0 20G
Command Purpose
qm createDefines the VM shell — ID, name, memory, network — with no disk attached yet.
import-from=Imports an existing disk image directly into a new VM disk, instead of a blank disk needing an OS installer.
--ide2 ...:cloudinitCreates the special cloud-init drive Proxmox uses to pass first-boot configuration into the guest.
--serial0 socket --vga serial0Cloud images ship configured for a serial console; without this the console can appear blank.
qm resizeCloud images ship deliberately small (often 2-3 GB); resize before converting so every future clone starts with enough room.

Once the VM boots cleanly and the cloud-init defaults look right, lock it as a template:

# Convert the VM into a template — after this it cannot be
# started again, only cloned
qm template 9000
Practical note: An existing hand-built VM can become a template too — shut it down, strip machine-specific state (SSH host keys, hostname, any embedded credentials) the same way you would before sysprep on Windows, then run qm template <vmid> on it directly. The cloud-init drive step above only applies if you want first-boot customization; a stripped manual VM still works as a template without it, just without automatic per-clone hostname/IP injection.

Cloning the Template

# Linked clone (default) — fast, minimal storage, depends
# on template 9000 continuing to exist
qm clone 9000 201 --name test-box-01

# Full clone — independent copy, costs full disk space
qm clone 9000 202 --name web-server-01 --full --storage local-lvm

# Clone to a different node (only works if the template
# lives on shared storage reachable from both nodes)
qm clone 9000 203 --name node2-clone --target pve2 --full

Customizing a Clone with Cloud-Init

A freshly cloned VM still has the template’s generic cloud-init defaults. Set the per-VM values before first boot so it comes up with its own identity instead of a copy of the template’s.

# Assign a static IP and gateway to the clone
qm set 201 --ipconfig0 ip=10.10.0.51/24,gw=10.10.0.1

# Set the SSH public key(s) the cloud-init user will trust
# (file path, one OpenSSH-format key per line)
qm set 201 --sshkeys ~/.ssh/id_rsa.pub

# Override the cloud-init user for this clone if needed
qm set 201 --ciuser labadmin

# Start it — cloud-init applies these settings on first boot
qm start 201
Important: Set cloud-init values with qm set before the first qm start. Cloud-init only reads and applies its configuration once, on that first boot — changing --ipconfig0 or --sshkeys after the VM has already booted once does nothing until the cloud-init drive is regenerated or the VM is cloned again.

Full Clone vs Linked Clone Cheat Sheet

Property Full Clone Linked Clone
Disk spaceFull size of the template’s diskOnly changed blocks (copy-on-write)
Creation speedSlower — every block is copiedFast — near-instant
Depends on templateNoYes — deleting the template breaks the clone
Supported storageAny storage typeqcow2/raw (local/NFS), LVM-thin, ZFS, RBD only
Best forProduction, cross-node movesDisposable lab and test VMs

Troubleshooting Cheat Sheet

Symptom Likely Cause Fix
qm clone fails with a storage error Target storage doesn’t support the requested clone type (e.g. linked clone on plain LVM). Use --full for that storage, or clone onto a storage type that supports copy-on-write (LVM-thin, ZFS, qcow2).
Clone boots but cloud-init settings never apply --ipconfig0/--sshkeys were set after the VM had already booted once. Regenerate the cloud-init drive from the GUI (Cloud-Init tab, Regenerate Image) or reset and reboot the VM so cloud-init reads the drive again.
Console shows a blank screen on a cloud-image VM Cloud images expect a serial console, not the default VGA display. Set qm set <vmid> --serial0 socket --vga serial0 and connect via the serial console in the GUI instead.
Cannot start a template This is expected behaviour — templates are permanently locked. Clone it first, start the clone. If you need to change the base image itself, clone it, edit the clone, then convert that clone into a new template.
Linked clone won’t delete — “in use” error Another linked clone (or the template) still references shared blocks. Remove or convert dependent clones first; a template with active linked clones cannot be deleted until they’re gone.
Cloned VM has the same hostname/SSH host keys as another clone The template was converted without stripping machine-specific state, and no cloud-init drive is present to regenerate it. Rebuild the template from a proper cloud image with a cloud-init drive attached, or manually run cloud-init clean and re-run sysprep/deprovisioning before converting.

Final Thoughts

Templates and clones turn a homelab from “reinstall an OS every time” into “clone a template and set an IP.” The setup cost is a single afternoon building one clean cloud-init template per distribution you use regularly; the payoff is every VM after that taking seconds instead of minutes, with a known-clean starting point every time.

Linked clones are the default for a reason, they are what makes rapid lab iteration cheap. Reach for full clones deliberately, when a VM needs to outlive the template or move to another node, not as the default habit.

Key takeaway: Build the template once with cloud-init attached, resize the disk before converting, and clone with qm clone <template> <newid> --name ... — add --full only when the clone needs to be independent of the template.
Next in this series

Next, we can cover Proxmox backup with vzdump and Proxmox Backup Server, and how backup strategy differs from what snapshots and clones already give you.