Cannot Lah

by shanscendent

Proxmox VM templates with cloud-init

March 15, 2025

Proxmox VM templates are preconfigured VM images that you can clone and launch other VMs from. Here are the steps to prepare an Ubuntu 24.04 VM template.

We assume you want a template with these options in the following instructions:

  • 9000 (Proxmox vmid)
  • noble-server-cloudimg-amd64.img (Ubuntu cloud image)
  • local-lvm (Proxmox storage)

Set up VM template

  • Download this image through the UI: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
  • Create a VM with no media and disk, set default CPU, memory and storage options for your VM clones
  • Import the Ubuntu cloud image as a disk and specify a format qm disk import 9000 /var/lib/vz/template/iso/noble-server-cloudimg-amd64.img local-lvm --format qcow2.
    • The qcow2 format supports snapshots
    • Note that if you’re using a LVM-Thin storage only the raw format is supported (which is the default format), so you can omit the --format parameter. It supports snapshots this way as well.
  • This disk shows up in the VM hardware tab as Unused Disk 0, double click it and add it
    • Enable the Discard and SSD emulation parameters
  • Change the boot order, enable scsi0 and disable the other options
  • Create the template with qm template 9000
  • Add sensible defaults like SSH keys and DNS servers to the cloud-init tab in the UI
    • To check what the auto generated user cloud-init is qm cloudinit dump 9000 user

Adding a vendor file to cloud-init

The default cloud-init generated by Proxmox has very limited options, so let’s add some additional options via cloud-init’s vendor data. Feel free to add more cloud-init options if you want to, but you most probably just want the ability to add more packages and run some bash commands.

mkdir -p /var/lib/vz/snippets
cat > /var/lib/vz/snippets/vendor.yaml << 'EOF'
#cloud-config
timezone: "Asia/Kuala_Lumpur"

package_update: true
package_upgrade: true
package_reboot_if_required: true

packages:
  - curl
  - git
  - python3-venv
  - qemu-guest-agent
  - unzip

runcmd:
  # install Docker
  - curl -fsSL https://get.docker.com -o get-docker.sh
  - sh get-docker.sh
  - rm get-docker.sh
  - groupadd docker
  - usermod -aG docker ubuntu
  - systemctl start qemu-guest-agent
EOF
qm set 9000 --cicustom "vendor=local:snippets/vendor.yaml"

Use

  • Right click this template VM and clone it in the UI (recommended to do a full clone)
    • Edit the options before you start it
      • In the Hardware tab, resize the scsi0 disk to the size you require
      • In the Cloud-Init tab, edit the password and SSH public key (user will default to ubuntu)
        • If you don’t give it a password, you won’t be able to login through the VM terminal in the Proxmox UI, but you can still SSH to it if you’ve added a public key
        • just give it a password like admin123, especially if you’re sharing Proxmox with other people, then change it in the VM
    • Since qemu-guest-agent is already installed, you should see the IP pop up in the Proxmox UI when it’s ready

Notes

  • Big raw image disks actually take a while to clone, it’s better to start with a small disk, then resize the main VM disk when the VM clone is created, cloud-init will automatically resize it with growpart and resizefs
    • This doesn’t seem to introduce any additional wear on the SSD though
  • When adding the user to the docker group, the user is hardcoded as ubuntu. Would be nicer to programmatically grab it from the Proxmox managed cloud-init as well.
    • If you create a user with a different name, you have to add it to the docker group again yourself
  • The Proxmox generated DNS nameserver settings don’t seem to work at all at the moment too

References