Free weekly email: the week's new posts, videos and one tip from the books, every Sunday. Get it free →
Homelab the Right Way

Home › Posts

Stop clicking through the installer: one cloud-init golden image for every Proxmox VM

Build one Debian 13 cloud-image template in Proxmox with qm create and cloud-init (user, SSH key, network, guest agent), then clone it for every new VM instead of running an installer.

· 4 min read · proxmoxcloud-initdebiantemplatesautomationhomelab

Stop clicking through the installer: one cloud-init golden image for every Proxmox VM

Every new VM that starts with an ISO and a click-through installer is a little different from the last one. A different username here, a forgotten SSH key there, a typo in a static address. Automate Your Homelab starts its rebuildable lab somewhere else: one template made from a distribution's official cloud image, cloned for every VM, with cloud-init filling in the personal details on first boot.

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.

The trap: hand-built VMs that drift

The installer route has two problems. It is slow, and it is not repeatable: nothing records what you typed, so the next VM only matches the last one if you remember every answer. A template built from commands fixes both. A template cannot be started, only cloned, and as the book puts it, that is the point: nobody logs into it, so it never drifts.

Pick the image

The book uses Debian 13 (trixie). Debian publishes cloud images at cloud.debian.org, and at the time of writing (October 2026) the trixie folder 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 commands below are the same for either.

Build the template once

Run these on the Proxmox host. They 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 local-lvm: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. If a particular image does not work with it, switch back to the default display.

Set the defaults every clone inherits

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 the guest agent on first boot

The Debian cloud image does not include the QEMU guest agent, and without it Proxmox (and OpenTofu, later in the book) 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. The catch: replacing user throws away the user and SSH key settings above. Add a vendor file instead, which cloud-init merges 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 and check what a clone will receive:

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

The dump command prints the user data Proxmox will generate, which is the quickest way to see what a clone gets. In a cluster, watch out: custom cloud-init files must be available on every node a VM may migrate to, or the VM will not start there. Use shared storage for snippets or copy the file to every node.

Turn it into a template, then clone

qm template 9000

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.

By default Proxmox tries to make a linked clone, which depends on the template. For a rebuildable lab the book prefers full clones (pass --full), because the template will be rebuilt whenever a new Debian point release arrives, and full clones do not care.

Keep the template fresh, and keep it in Git

Cloud images are rebuilt regularly with current packages. Every few months, or when a Debian point release comes out, download the new image and create the template again under the same ID, so new VMs start current. Because every step is a command, the rebuild is a script: save the commands as cloud-init/build-template.sh in your lab's repository, and keep the vendor snippet in the repository's cloud-init/ folder too. The copy on the Proxmox host is just a deployment of it.

Checklist

  • Download debian-13-genericcloud-amd64.qcow2, not the generic image, for Proxmox VMs.
  • Create the VM with VirtIO networking, the VirtIO SCSI controller and --agent enabled=1.
  • Import the image with import-from, add the cloudinit drive on ide2, boot from scsi0, serial console on.
  • Set --ciuser, --sshkeys, --ipconfig0 and DNS on the template; skip --cipassword.
  • Add qemu-guest-agent through a vendor snippet, never by replacing user data.
  • Check the result with qm cloudinit dump 9000 user before running qm template 9000.
  • Clone with --full, set the clone's address, grow its disk, start it.
  • Save the build as cloud-init/build-template.sh and rebuild on each Debian point release.

More articles