How to create VM template in Proxmox VE from Ubuntu Cloud-Init image

This is a simple guide to create a reusable VM template in Proxmox VE from an Ubuntu Cloud-Init Image. I've documented this process for my own reference as I'm still learning Proxmox, but thought it might be useful to share.

I’m running a Proxmox VE v7.4 cluster, and will be using Ubuntu 22.04 (Jammy) Cloud image as the base for the template.

Without further ado, let's get started!

Create the Base VM

First, gain access into the physical node (via ssh) where you want to the VM template to be created.

Run the command below to create a new VM with basic specifications.

~# qm create 9001 --memory 2048 --core 2 --name template --net0 virtio,bridge=vmbr1

I’m allocating 2GB for memory and 2 cores for CPU for a minimalistic setup, and assigning the VM an ID 9001 and name template . You're free to configure the VM however you want.

This creates a .conf file under /etc/pve/qemu-server/ that can be edited manually, but using the qm command is recommended.

You can locate the file by its ID as follow:

~# ls /etc/pve/qemu-server/9001.conf 

Check Available Storage Pools

You'd first identify what storage pools are configured for the physical node that you're currently working on. Run this command to find out:

~# pvesm status

Name         Type     Status           Total            Used       Available        %
local         dir     active      1740823328      1234441696       417878952   70.91%

In my case, the local storage is the only option I have, and I'll be using this storage pool throughout this guide.

Download the Cloud Image

If you're using an Ubuntu cloud image like I do, you can grab the image from the official source: https://cloud-images.ubuntu.com/. These images come with a lean Ubuntu system with built-in Cloud-Init specifically for cloud environments.

I have my image downloaded onto the node's local storage. You can download to any other storage types (e.g. ZFS, LVM) that are available to you.

Proxmox VE also provides a hassle-free way to download the image by simply passing in the image URL.

To list the images available in your storage:

~# pvesm list local

local:iso/jammy-server-cloudimg-amd64.img    iso     iso          678153216

Import the Cloud Image as a VM Disk

Run the command below to import the cloud image into the VM as a new virtual disk.

~# qm importdisk 9001 jammy-server-cloudimg-amd64.img local

importing disk 'jammy-server-cloudimg-amd64.img' to VM 9001 ...
Formatting '/var/lib/vz/images/9001/vm-9001-disk-0.raw', fmt=raw size=2361393152 preallocation=off
transferred 0.0 B of 2.2 GiB (0.00%)
transferred 22.5 MiB of 2.2 GiB (1.00%)
transferred 45.0 MiB of 2.2 GiB (2.00%)
...
transferred 2.2 GiB of 2.2 GiB (100.00%)
transferred 2.2 GiB of 2.2 GiB (100.00%)
Successfully imported disk as 'unused0:local:9001/vm-9001-disk-0.raw'

This copies the image into your chosen storage pool (e.g. local) and creates a new virtual disk for that VM.

The imported image will be added as an unused disk in the VM's hardware configuration, meaning it is available but not yet attached to a specific bus or device inside the VM.

To verify the creation of the disk:

~# pvesm list local

Volid                                        Format  Type              Size VMID
local:9001/vm-9001-disk-0.raw                raw     images      2361393152 9001
local:iso/jammy-server-cloudimg-amd64.img    iso     iso          678153216

This is what the Hardware tab looks like for the VM at this stage:

Attach the Disk to the VM

To allow the VM to boot from the imported disk, you'll have to attach the disk to the VM by running this command:

~# qm set 9001 --scsihw virtio-scsi-pci --scsi0 local:9001/vm-9001-disk-0.raw 

update VM 9001: -scsi0 local:9001/vm-9001-disk-0.raw -scsihw virtio-scsi-pci

This sets the SCSI controller for the VM and attaches the disk image as the first SCSI disk (scsi0) on that controller .

Add a Cloud-Init Drive

Run the following command to create and attach a Cloud-Init drive to the VM on the IDE2 device interface. 

~# qm set 9001 --ide2 local:cloudinit

update VM 9001: -ide2 local:cloudinit
Formatting '/var/lib/vz/images/9001/vm-9001-cloudinit.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=4194304 lazy_refcounts=off refcount_bits=16
ide2: successfully created disk 'local:9001/vm-9001-cloudinit.qcow2,media=cdrom'
generating cloud-init ISO

The Cloud-Init drive is typically attached as a CD-ROM or virtual disk so the guest OS can read configuration data such as hostname, SSH keys, network settings etc. to initialise the system accordingly during the first boot.

Cloud-Init drive in Proxmox VE works by generating an ISO image to pass the Cloud-Init data to the VM when attached as a CD-ROM. For that purpose, all Cloud-Init VMs need to have an assigned CD-ROM drive.

To verify that the Cloud-Init drive was successfully created:

~# pvesm list local

Volid                                        Format  Type              Size VMID
local:9001/vm-9001-cloudinit.qcow2           qcow2   images         4194304 9001
local:9001/vm-9001-disk-0.raw                raw     images      2361393152 9001
local:iso/jammy-server-cloudimg-amd64.img    iso     iso          678153216

Configure Boot Options

Now, set the VM to boot from the imported (primary) disk attached at scsi0:

~# qm set 9001 --boot order=scsi0

Configure Display Options

For Cloud-Init images, it's often necessary to configure a serial console:

~# qm set 9001 --serial0 socket --vga serial0

update VM 9001: -serial0 socket -vga serial0

This is what the Hardware tab of the VM looks like after going through all the steps.

Final Configuration and Template Conversion

Before converting into a template, you should review and make any final adjustments to the VM (memory, CPU, disk space, etc.).

Then, go to the Cloud-Init tab and fill out the necessary settings (user, password, SSH keys). I’d typically leave out the IP Config settings to avoid hardcoding network settings (especially IP addresses) inside the template.

As final step, convert the VM into a template by right-clicking on it on the sidebar and selecting Convert to template .

And we’re done! 🥳


Using the Template

To deploy a new VM from your template, you simply have to:

  • Clone the template into a new VM by right-clicking on the template → Clone , and fill out the details in the pop-up window.
  • Adjust the hardware settings of the cloned VM if needed (memory, CPU, disk).
  • Edit the VM’s Cloud-Init settings (e.g. to give it a static IP and a gateway).
  • Start the VM.

That's it! This process saves a lot of time when you need to deploy multiple similar VMs from a Cloud-Init template with minimal effort.


References

https://pve.proxmox.com/wiki/Cloud-Init_Support