Skip to content
Hogin Hogin
Go back

Proxmox Cloud-Init 24.04 Tutorial

5 мин чтения

Creating an Ubuntu 24.04 Virtual Machine Template for Proxmox and Cloud-Init

This is a brief guide to setting up an Ubuntu virtual machine template in Proxmox using Cloud-Init in a scripted manner.

For this guide, I’ve made a few assumptions:

The Basics

The first step is to download the cloud image for Ubuntu, then we’ll resize that image

wget -q https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
qemu-img resize noble-server-cloudimg-amd64.img 32G

Note that even though I resize this image to 32 gigabytes, the file size won’t actually be 32 gigabytes — that’s because the image is what’s known as a sparse file. The image starts at ~2 GB, but if we don’t resize the image now, any cloned virtual machines won’t have room for storage. Feel free to change the 32 GB to 20, 80, or whatever else you like.

Creating the Virtual Machine

The next step is to create the base virtual machine that we’ll build on:

sudo qm create 8001 --name "ubuntu-2404-cloudinit-template" --ostype l26 \
--memory 1024 \
--agent 1 \
--bios ovmf --machine q35 --efidisk0 local-zfs:0,pre-enrolled-keys=0 \
--cpu host --socket 1 --cores 1 \
--vga serial0 --serial0 socket \
--net0 virtio,bridge=vmbr0

Feel free to change 8001 to whatever you like, just make sure you replace 8001 in the subsequent commands with whatever you chose. The amount of memory selected doesn’t matter, since this particular virtual machine won’t be booted — be sure to adjust the amount of RAM for the cloned virtual machines. --agent enables the QEMU guest agent, which is useful for various things, such as viewing the IP addresses of any interfaces. We’ll set the CPU type to host (you almost always want this) with a single socket and a single core (don’t forget to change the core count on the cloned virtual machines). Next comes the GPU; you can choose virtio instead of serial0 if you want, but it isn’t necessary; the serial GPU type allows copy and paste, which can be handy. Finally, the network adapter — if you have a specific bridge interface you want to select, change vmbr0 to whatever it is. If you want to use a VLAN tag, add ,tag=## right after the bridge name (no spaces)

Hardware Setup

sudo qm importdisk 8001 noble-server-cloudimg-amd64.img local-zfs
sudo qm set 8001 --scsihw virtio-scsi-pci --virtio0 local-zfs:vm-8001-disk-1,discard=on
sudo qm set 8001 --boot order=virtio0
sudo qm set 8001 --scsi1 local-zfs:cloudinit

The first command imports the image we downloaded earlier; if your disk storage isn’t local-zfs (for example, local-lvm), then replace it with what you need. The next command attaches the disk to the virtual machine. If your disk storage isn’t on an SSD (and it should be), omit ,discard=on. The third command sets the boot order. The fourth adds the cloud-init pseudo-CDROM drive.

Creating the vendor.yaml File for Cloud-Init

cat << EOF | sudo tee /var/lib/vz/snippets/vendor.yaml
#cloud-config
runcmd:
- apt update
- apt install -y qemu-guest-agent
- systemctl start qemu-guest-agent
- reboot

EOF

This file serves two purposes — the first is fairly obvious (installing qemu-guest-agent), the second not so much. For some reason, Cloud-Init runs after the network connection comes up, so you can’t use SSH or even ping the virtual machine by the name you give it. This package runs only once, so after this reboot you’ll be able to use the virtual machine.

Configuring Cloud-Init

sudo qm set 8001 --cicustom "vendor=local:snippets/vendor.yaml"
sudo qm set 8001 --tags ubuntu-template,24.04,cloudinit
sudo qm set 8001 --ciuser untouchedwagons
sudo qm set 8001 --cipassword $(openssl passwd -6 $CLEARTEXT_PASSWORD)
sudo qm set 8001 --sshkeys ~/.ssh/authorized_keys
sudo qm set 8001 --ipconfig0 ip=dhcp

The first command tells CI to use the vendor file we specified earlier. The second can be skipped, but it adds decorative tags that show up in the Proxmox web interface. Cloned virtual machines inherit all of these tags. The third specifies the user to create. The fourth sets the password. The fifth imports the public SSH keys so you can log in via SSH. Finally, the virtio network adapter is set to DHCP — this is supposed to be the default, but it needs to be specified manually.

Finally: Converting to a Template

sudo qm template 8001

That’s it! Your template is now ready to use. Clone this template as you see fit (don’t forget to adjust the cores and RAM as needed) and start the clone. On the first boot, Cloud-Init will run, create your user, install qemu-guest-agent, and reboot. Once the reboot completes, you can use SSH and use the virtual machine however you like!

Example Script

A script to create Proxmox templates for you. At the top of the file are two environment variables that will need to be adjusted to match how your Proxmox is configured.

#! /bin/bash

VMID=8200
STORAGE=local-zfs

set -x
rm -f noble-server-cloudimg-amd64.img
wget -q https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
qemu-img resize noble-server-cloudimg-amd64.img 8G
sudo qm destroy $VMID
sudo qm create $VMID --name "ubuntu-noble-template" --ostype l26 \
    --memory 1024 --balloon 0 \
    --agent 1 \
    --bios ovmf --machine q35 --efidisk0 $STORAGE:0,pre-enrolled-keys=0 \
    --cpu host --cores 1 --numa 1 \
    --vga serial0 --serial0 socket  \
    --net0 virtio,bridge=vmbr0,mtu=1
sudo qm importdisk $VMID noble-server-cloudimg-amd64.img $STORAGE
sudo qm set $VMID --scsihw virtio-scsi-pci --virtio0 $STORAGE:vm-$VMID-disk-1,discard=on
sudo qm set $VMID --boot order=virtio0
sudo qm set $VMID --scsi1 $STORAGE:cloudinit

cat << EOF | sudo tee /var/lib/vz/snippets/ubuntu.yaml
#cloud-config
runcmd:
    - apt-get update
    - apt-get install -y qemu-guest-agent
    - systemctl enable ssh
    - reboot
# Taken from https://forum.proxmox.com/threads/combining-custom-cloud-init-with-auto-generated.59008/page-3#post-428772
EOF

sudo qm set $VMID --cicustom "vendor=local:snippets/ubuntu.yaml"
sudo qm set $VMID --tags ubuntu-template,noble,cloudinit
sudo qm set $VMID --ciuser $USER
sudo qm set $VMID --sshkeys ~/.ssh/authorized_keys
sudo qm set $VMID --ipconfig0 ip=dhcp
sudo qm template $VMID

Share this post:

Previous Post
Getting Started with Docker
Next Post
Order in IT: On the Importance of Pulling Up Baobabs