Creatingrepeatable and secure VM templatesin Proxmox has been a game-changer in refining and scaling my homelab environment.
In this post, I’ll show you how to:
- Use the NoCloud datasource with Ubuntu Cloud Images
- Inject SSH keys from your admin box
- Enable and verify the Proxmox guest agent
- Clone pre-configured VMs using Proxmox CLI Let’s walk through the whole process—from image preparation to SSH-ready VM deployment.
For the latest Ubuntu Cloud images, you can checkUbuntu Cloud Images.
Step 1: Download the Ubuntu Cloud Image
From yourProxmox server, download the latest Ubuntu 24.04 cloud image:
wget -P /var/lib/vz/template/iso/ \
https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img
wget -P /var/lib/vz/template/iso/ \
https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img
Then verify:
ls /var/lib/vz/template/iso/ | grep -i ubuntu-
ls /var/lib/vz/template/iso/ | grep -i ubuntu-
You should see theubuntu-24.04-server-cloudimg-amd64.imgfile listed.
ubuntu-24.04-server-cloudimg-amd64.img
Step 2: Create a Base VM Template
2.1 Create the VM
First, create the base VM that will serve as your Ubuntu template. We’re using ID501, but you can choose any unused ID.
501
qm create 501 \
--name ubuntu-cloud-init-template \
--memory 2048 \
--cores 2 \
--net0 virtio,bridge=vmbr0
qm create 501 \
--name ubuntu-cloud-init-template \
--memory 2048 \
--cores 2 \
--net0 virtio,bridge=vmbr0
2.2 Import the disk
Next, import the Ubuntu cloud image as a virtual disk into your Proxmox storage (in this case,local-zfs).
local-zfs
qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs
qm importdisk 501 /var/lib/vz/template/iso/ubuntu-24.04-server-cloudimg-amd64.img local-zfs
2.3 Set the VM disk and boot options
qm set 501 \
--scsihw virtio-scsi-pci \
--scsi0 local-zfs:vm-501-disk-0 \
--boot c \
--bootdisk scsi0
qm set 501 \
--scsihw virtio-scsi-pci \
--scsi0 local-zfs:vm-501-disk-0 \
--boot c \
--bootdisk scsi0
2.4 Attach Cloud-init disk
qm set 501 --ide2 local-zfs:cloudinit
qm set 501 --ide2 local-zfs:cloudinit
2.5 Enable the qemu-guest-agent
qm set 501 --agent enabled=1
qm set 501 --agent enabled=1
Step 3: Generate SSH Keys & NoCloud ISO
I’ll generate thessh-keysfrom myMac, but any admin workstation will do.
ssh-keys
3.1 Generate a dedicated SSH key
ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template
ssh-keygen -t ed25519 -C "ubuntu-template" -f ~/.ssh/id_ed25519_ubuntu_template
This creates:
- ~/.ssh/id_ed25519_ubuntu_template
~/.ssh/id_ed25519_ubuntu_template
- ~/.ssh/id_ed25519_ubuntu_template.pub
~/.ssh/id_ed25519_ubuntu_template.pub
3.2 Copy the public key
pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub
pbcopy < ~/.ssh/id_ed25519_ubuntu_template.pub
3.3 Createuser-dataandmeta-data(cloud-init)
user-data
meta-data
I’ll create the cloud-init configuration files that tell the VM how to initialize on first boot—things like hostname, users, and packages. Theuser-datafile contains most of the logic, whilemeta-datajust defines identity info for the instance.
user-data
meta-data
mkdir -p /root/cloudinit/ubuntu-template
cd /root/cloudinit/ubuntu-template
mkdir -p /root/cloudinit/ubuntu-template
cd /root/cloudinit/ubuntu-template
Create the following files:user-data
user-data
#cloud-config
hostname: ubuntu-template
users:
- name: ubuntu
ssh-authorized-keys:
- paste_the_public_key_you_copied_earlier
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
#cloud-config
hostname: ubuntu-template
users:
- name: ubuntu
ssh-authorized-keys:
- paste_the_public_key_you_copied_earlier
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
meta-data
meta-data
instance-id: ubuntu-template
local-hostname: ubuntu-template
instance-id: ubuntu-template
local-hostname: ubuntu-template
3.4 Generate the ISO (on Proxmox)
Make sure you havecloud-image-utilsinstalled:
cloud-image-utils
apt update
apt install cloud-image-utils
apt update
apt install cloud-image-utils
This gives you access to thecloud-localdscommand you need.
This gives you access to thecloud-localdscommand you need.
cloud-localds
Then, generate the iso:
cloud-localds nocloud.iso user-data meta-data
cloud-localds nocloud.iso user-data meta-data
3.5 Move ISO to/var/lib/vz/template/iso/
/var/lib/vz/template/iso/
mv nocloud.iso /var/lib/vz/template/iso/
mv nocloud.iso /var/lib/vz/template/iso/
If your Proxmox storage useslocal-lvminstead oflocal-zfs, adjust the path accordingly.You can check available storage with:pvesm status
If your Proxmox storage useslocal-lvminstead oflocal-zfs, adjust the path accordingly.You can check available storage with:pvesm status
local-lvm
local-zfs
pvesm status
3.6 Attach ISO to VM
qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom
qm set 501 --ide2 local:iso/nocloud.iso,media=cdrom
Replacelocalif your ISO storage is named differently — usepvesm statusto check.
Replacelocalif your ISO storage is named differently — usepvesm statusto check.
local
pvesm status
Step 4: Convert to a Template
Once your base VM is configured, convert it to a Proxmox template so you can quickly clone new VMs from it.
qm template 501
qm template 501
Step 5: Clone and Deploy
5.1 Clone the template
qm clone 501 105 --name "ubuntu-vm01"
qm clone 501 105 --name "ubuntu-vm01"
5.2 Customize the new VM
qm set 105 --memory 4096 --cores 4
qm set 105 --memory 4096 --cores 4
5.3 Start up the VM
qm start 105
qm start 105
Remember to update the new IP address of the server in your~/.ssh/configfile, as shown below.
Remember to update the new IP address of the server in your~/.ssh/configfile, as shown below.
~/.ssh/config
~/.ssh/config
~/.ssh/config
Host ubuntu
HostName 10.160.0.64
User ubuntu
IdentityFile ~/.ssh/id_ed25519_ubuntu_template
Host ubuntu
HostName 10.160.0.64
User ubuntu
IdentityFile ~/.ssh/id_ed25519_ubuntu_template
Now you can typessh ubuntuto connect to your newly created VM.
ssh ubuntu
I use this setup regularly when provisioning dev servers or test environments—it saves a ton of time.
You now have a clean and SSH-ready NoCloud Ubuntu template:
- Ideal for hands-off provisioning
- Cloud-init friendly
- Guest agent enabled out of the box Found this helpful?Check out moretech tutorialsor follow myGitHub, where I share homelab setups, automation tools, and real-world projects from my day-to-day work as an IT consultant.
Originally published at https://kjetilfuras.com/provision-ubuntu-vms-with-nocloud-on-proxmox/
Top comments (0)