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.
A read-only base VM. It cannot be started, only cloned.
An independent copy of every disk. Costs full disk space, owes nothing to the template.
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.
Full Clone or Linked Clone?
The choice is a trade-off between independence and speed, not a universal “better” option.
Production VMs, anything you might migrate to another node, or VMs that must survive the template being deleted.
Disposable lab VMs, quick throwaway test boxes, anything you rebuild from scratch more often than you keep long-term.
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 create | Defines 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 ...:cloudinit | Creates the special cloud-init drive Proxmox uses to pass first-boot configuration into the guest. |
--serial0 socket --vga serial0 | Cloud images ship configured for a serial console; without this the console can appear blank. |
qm resize | Cloud 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
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
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 space | Full size of the template’s disk | Only changed blocks (copy-on-write) |
| Creation speed | Slower — every block is copied | Fast — near-instant |
| Depends on template | No | Yes — deleting the template breaks the clone |
| Supported storage | Any storage type | qcow2/raw (local/NFS), LVM-thin, ZFS, RBD only |
| Best for | Production, cross-node moves | Disposable 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.
qm clone <template> <newid> --name ... — add --full only when the clone needs to be independent of the template.
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.