Skip to content

Ubuntu Server

Purpose

You may need to deploy many copies of a virtual machine rapidly, and don't want to go through the hassle of setting up everything ad-hoc as the needs arise for each VM workload. Creating a cloud-init template allows you to more rapidly deploy production-ready copies of a template VM (that you create below) into a ProxmoxVE environment.

Download Image and Import into ProxmoxVE

You will first need to pull down the OS image from Ubuntu's website via CLI, as there is currently no way to do this via the WebUI. Using SSH or the Shell within the WebUI of one of the ProxmoxVE servers, run the following commands to download and import the image into ProxmoxVE.

# Make a place to keep cloud images
mkdir -p /var/lib/vz/template/images/ubuntu && cd /var/lib/vz/template/images/ubuntu

# Download Ubuntu 24.04 LTS cloud image (amd64, server)
wget -q --show-progress https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

# Create a Placeholder VM to Attach Cloud Image
qm create 9000 --name ubuntu-2404-cloud --memory 8192 --cores 8 --net0 virtio,bridge=vmbr0

# Set UEFI (OVMF) + SCSI controller (Cloud images expect UEFI firmware and SCSI disk.)
qm set 9000 --bios ovmf --scsihw virtio-scsi-pci
qm set 9000 --efidisk0 nfs-cluster-storage:0,pre-enrolled-keys=1

# Import the disk into ProxmoxVE
qm importdisk 9000 noble-server-cloudimg-amd64.img nfs-cluster-storage --format qcow2

# Query ProxmoxVE to find out where the volume was created
pvesm list nfs-cluster-storage | grep 9000

# Attach the disk to the placeholder VM
qm set 9000 --scsi0 nfs-cluster-storage:9000/vm-9000-disk-0.qcow2

# Configure Disk to Boot
qm set 9000 --boot c --bootdisk scsi0

Add Cloud-Init Drive & Configure Template Defaults

Now that the Ubuntu cloud image is attached as the VM’s primary disk, you need to attach a Cloud-Init drive. This special drive is where Proxmox writes your user data (username, SSH keys, network settings, etc.) at clone time.

# Add a Cloud-Init drive to the VM
qm set 9000 --ide2 nfs-cluster-storage:cloudinit

# Enable QEMU Guest Agent
qm set 9000 --agent enabled=1

# Set a default Cloud-Init user (replace 'nicole' with your preferred username)
qm set 9000 --ciuser nicole

# Set a default password (this will be resettable per-clone)
qm set 9000 --cipassword 'SuperSecretPassword'

# Set DNS Servers and Search Domain
qm set 9000 --nameserver "1.1.1.1 1.0.0.1"
qm set 9000 --searchdomain bunny-lab.io

# Enable automatic package upgrades within the VM on first boot
qm set 9000 --ciupgrade 1

# Download your infrastructure public SSH key onto the Proxmox node
wget -O /root/infrastructure_id_rsa.pub \
  https://git.bunny-lab.io/Infrastructure/LinuxServer_SSH_PublicKey/raw/branch/main/id_rsa.pub

# Tell Proxmox to inject this key via Cloud-Init
qm set 9000 --sshkey /root/infrastructure_id_rsa.pub

# Configure networking to use DHCP by default (this will be overridden at cloning)
qm set 9000 --ipconfig0 ip=dhcp

Setup Packages in VM & Convert to Template

At this point, we have a few things we need to do first before we can turn the VM into a template and make clones of it. You will need to boot up the VM we made (id 9000) and run the following commands to prepare it for becoming a template:

# Install Updates
sudo apt update && sudo apt upgrade
sudo apt install -y qemu-guest-agent cloud-init
sudo systemctl enable qemu-guest-agent --now

# Magic Stuff Goes Here =============================

# Convert the placeholder VM into a reusable template (ignore chattr errors on NFS storage backends)
qm template 9000

Clone the Template into a New VM

You can now create new VMs instantly from the template we created above.

  • Log into the ProxmoxVE node where the template was created
  • Right-Click the Template > "Clone"
  • Give the new VM a name
  • Set the "Mode" of the clone to "Full Clone"
  • Navigate to the new GuestVM in ProxmoxVE and click on the "Cloud-Init" tab
  • Change the "User" and "Password" fields if you want to change them
  • Double-click on the "IP Config (net0)" option
    • IPv4/CIDR: 192.168.3.67/24
    • Gateway (IPv4): 192.168.3.1
    • Click the "OK" button
  • Start the VM and wait for it to automatically provision itself
# Create a new VM (example: VM 9100) cloned from the template
qm clone 9000 9100 --name ubuntu-2404-test --full

# Optionally, override Cloud-Init settings for this clone:
qm set 9100 --ciuser nicole --cipassword 'AnotherStrongPass'
qm set 9100 --ipconfig0 ip=192.168.3.67/24,gw=192.168.3.1

# Boot the new cloned VM
qm start 9100

Configure VM Hostname

At this point, the hostname of the VM will be randomized and you will probably want to set it to something statically, you can do that with the following commands after the server has finished starting: