Every VM in a rebuildable lab starts from the same place: a template made from a distribution's official cloud image. Cloud images are small, minimal installs built to be configured on first boot by cloud-init, which reads its settings from a little drive that Proxmox attaches to the VM. That is how a fresh clone wakes up with the right hostname, your user, your SSH key and its address, without anyone touching a console.

Pick the image

Debian publishes cloud images at cloud.debian.org. At the time of writing (October 2026) the latest folder for trixie (Debian 13) holds, among others:

  • debian-13-genericcloud-amd64.qcow2: for cloud and virtual machines, with a smaller set of hardware drivers. This is the one for Proxmox VMs.
  • debian-13-generic-amd64.qcow2: the same system with a wider set of drivers, for odd hardware.

Ubuntu publishes its own cloud images at cloud-images.ubuntu.com, and the Proxmox documentation uses one in its example. The commands below are the same for either.

Build the template by hand, once

Run these on the Proxmox host. The steps follow the Proxmox VE Cloud-Init Support documentation; VM ID 9000 and the storage names are examples.

cd /var/lib/vz/template/iso wget https://cloud.debian.org/images/cloud/trixie/latest/\ debian-13-genericcloud-amd64.qcow2 qm create 9000 --name debian13-tmpl --memory 2048 \ --cores 2 --net0 virtio,bridge=vmbr0 \ --scsihw virtio-scsi-pci --ostype l26 --agent enabled=1 qm set 9000 --scsi0 local-lvm:0,import-from=\ /var/lib/vz/template/iso/debian-13-genericcloud-amd64.qcow2 qm set 9000 --ide2 local-lvm:cloudinit qm set 9000 --boot order=scsi0 qm set 9000 --serial0 socket --vga serial0 

What each step does:

  • qm create makes an empty VM with a VirtIO network card on bridge vmbr0 and the VirtIO SCSI controller that cloud images expect.
  • import-from copies the downloaded image into a new disk on local-lvm and attaches it as scsi0.
  • --ide2 ...:cloudinit adds the small cloud-init drive. Proxmox writes the user, network and SSH settings onto it.
  • --boot order=scsi0 boots straight from the disk, skipping the CD-ROM check.
  • The serial console is what many cloud images expect as their display. The Proxmox docs note that if a particular image does not work with it, you switch back to the default display.

Set the cloud-init defaults

Settings made on the template are inherited by every clone, so put the parts that are the same everywhere here:

qm set 9000 --ciuser admin qm set 9000 --sshkeys /root/admin_ed25519.pub qm set 9000 --ipconfig0 ip=dhcp qm set 9000 --searchdomain home.example.com \ --nameserver 192.168.20.1 

--sshkeys takes a file with one public key per line. Use keys, not --cipassword; the Proxmox documentation itself says passwords are generally not recommended here.

Add your own first-boot steps

The most common extra is the QEMU guest agent: the Debian cloud image does not include it, and without it Proxmox (and any tooling that asks Proxmox) cannot read the VM's address or shut it down cleanly.

The --cicustom option lets you supply your own files in place of the generated ones. It accepts user, network, meta and vendor files. Replacing user throws away the user and SSH key settings above, so add a vendor file instead: cloud-init merges it with the generated user data.

Custom files must live on a storage that allows the snippets content type. On the default local storage that is /var/lib/vz/snippets/. Enable the content type under Datacenter > Storage > local > Content, then create the file:

#cloud-config # /var/lib/vz/snippets/debian-vendor.yaml package_update: true packages: - qemu-guest-agent runcmd: - systemctl enable --now qemu-guest-agent 

Attach it to the template and look at what a clone will receive:

qm set 9000 --cicustom "vendor=local:snippets/debian-vendor.yaml" qm cloudinit dump 9000 user 

Watch out: the Proxmox docs point out that custom cloud-init files must be available on every node a VM may migrate to, or the VM will not start there. In a cluster, use shared storage for snippets or copy the file to every node.

Turn it into a template

qm template 9000 

A template cannot be started; it can only be cloned. That is the point: nobody logs into it, so it never drifts.

Clone and personalize

qm clone 9000 120 --name docker01 qm set 120 --ipconfig0 ip=192.168.20.120/24,gw=192.168.20.1 qm disk resize 120 scsi0 20G qm start 120 

After a minute, ssh admin@192.168.20.120 should work with your key. The cloud image's disk is small, which is why the clone's disk is grown with qm disk resize; cloud-init grows the root filesystem to fill it on boot.

Linked or full clones

When you clone a template, Proxmox tries to make a linked clone by default: the new disk only stores the differences from the template's disk. It is fast and small. The catch is that the clone depends on the template; you cannot delete the template while linked clones exist, and not every storage type supports them. Pass --full to get an independent copy.

For a rebuildable lab, full clones are usually the better default. The template will be rebuilt whenever a new Debian point release arrives, and full clones do not care.

Checklist

  • Debian 13 genericcloud image imported, cloud-init drive added, serial console set.
  • User, SSH key, DNS and search domain set on the template, not on each clone.
  • A vendor snippet installs qemu-guest-agent; qm cloudinit dump shows it merged in.
  • qm template run; clones made with --full.
  • The snippet is kept in your repository; the copy on the Proxmox host is just a deployment of it.

This is adapted from my book Automate Your Homelab (Homelab the Right Way, Book 9). The free sample is here and the full book is here.

Want the week's homelab articles, videos and one tip from the books in your inbox every Sunday? Get the free weekly email.

Drafted with AI help and edited by the author; based on his book.