Using Cloud-Init Templates in Proxmox VE
Automate VM provisioning with cloud-init templates in Proxmox VE. Create VMs in seconds with pre-configured networking and packages.
What Is Cloud-Init?
Cloud-init is an industry-standard tool for automating the initial configuration of virtual machines at first boot. It handles tasks like setting the hostname, creating user accounts, injecting SSH keys, configuring network interfaces, and running custom scripts — all without manual intervention. Originally developed for cloud platforms like AWS and OpenStack, cloud-init is now supported natively in Proxmox VE, making it possible to deploy fully configured VMs in seconds.
Instead of installing an operating system from scratch each time you need a new VM, you download a pre-built cloud image, convert it into a Proxmox template, and then clone it whenever you need a new machine. Cloud-init personalizes each clone at first boot — different hostname, different IP address, different SSH keys — all automatically.
Why Use Cloud-Init Templates?
- Speed: Deploy a fully configured VM in under 30 seconds instead of spending 15-20 minutes on a manual OS installation.
- Consistency: Every VM starts from the same base image, eliminating configuration drift.
- Automation: Integrate with scripts and infrastructure-as-code tools for hands-off provisioning.
- Resource efficiency: Cloud images are minimal installations, typically 300-500 MB, without unnecessary packages.
Step 1: Download a Cloud Image
Most major Linux distributions provide official cloud images. Download one to your Proxmox server:
# Ubuntu 24.04 LTS cloud image
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
# Debian 12 cloud image
wget https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2
# Rocky Linux 9 cloud image
wget https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base.latest.x86_64.qcow2
Step 2: Create a VM and Import the Disk
Create a new VM shell using the Proxmox CLI, then import the downloaded cloud image as its disk:
# Create a new VM (ID 9000) as our template base
qm create 9000 --name "ubuntu-cloud-template" --memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
# Import the cloud image to your storage (replace 'local-lvm' with your storage name)
qm importdisk 9000 noble-server-cloudimg-amd64.img local-lvm
# Attach the imported disk as the main drive
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0
# Set the boot order
qm set 9000 --boot order=scsi0
# Add a cloud-init drive (this is where Proxmox stores cloud-init configuration)
qm set 9000 --ide2 local-lvm:cloudinit
# Configure the serial console and display
qm set 9000 --serial0 socket --vga serial0
# Set the VM to use UEFI (optional but recommended for modern images)
qm set 9000 --bios ovmf --machine q35 --efidisk0 local-lvm:1,format=raw,efitype=4m,pre-enrolled-keys=1
Step 3: Configure Cloud-Init Settings
Now configure the default cloud-init parameters that will apply to VMs cloned from this template. You can do this through the web UI (select the VM > Cloud-Init tab) or from the command line:
# Set default user and password
qm set 9000 --ciuser admin --cipassword $(openssl passwd -6 'yourpassword')
# Add SSH public key for passwordless access
qm set 9000 --sshkeys ~/.ssh/authorized_keys
# Configure networking (DHCP or static)
qm set 9000 --ipconfig0 ip=dhcp
# Or use a static IP:
# qm set 9000 --ipconfig0 ip=10.0.0.100/24,gw=10.0.0.1
# Set DNS
qm set 9000 --nameserver 1.1.1.1 --searchdomain example.com
These settings are stored on the cloud-init drive and injected into the VM at first boot.
Step 4: Resize the Disk (Optional)
Cloud images ship with small disks (usually 2-3 GB). Resize the disk to your preferred default size before converting to a template:
qm resize 9000 scsi0 32G
Cloud-init will automatically expand the filesystem to fill the resized disk at first boot.
Step 5: Convert to a Template
Once everything is configured, convert the VM into a template:
qm template 9000
This marks the VM as a template in Proxmox. It can no longer be started directly — it can only be cloned.
Cloning Templates
To create a new VM from your template, use the clone operation:
# Full clone (independent copy of the disk)
qm clone 9000 101 --name "web-server-01" --full
# Linked clone (shares base disk, uses less storage but depends on template)
qm clone 9000 102 --name "dev-server-01"
After cloning, customize the cloud-init settings for the new VM before starting it:
# Set a unique IP for this clone
qm set 101 --ipconfig0 ip=10.0.0.101/24,gw=10.0.0.1
# Change the hostname
qm set 101 --name "web-server-01"
# Start the VM — cloud-init runs on first boot
qm start 101
Within 15-20 seconds, the VM will be fully booted with the correct hostname, IP address, and SSH keys configured.
Using Cloud-Init Snippets for Advanced Configuration
For more complex first-boot tasks — installing packages, configuring services, running scripts — Proxmox supports cloud-init custom snippets. These are YAML files stored on a Proxmox storage that has "Snippets" enabled.
# Create a snippet directory on your storage
mkdir -p /var/lib/vz/snippets
# Create a custom cloud-init user-data snippet
cat > /var/lib/vz/snippets/web-server-init.yml << 'EOF'
#cloud-config
package_update: true
package_upgrade: true
packages:
- nginx
- certbot
- python3-certbot-nginx
- ufw
runcmd:
- systemctl enable nginx
- systemctl start nginx
- ufw allow 'Nginx Full'
- ufw --force enable
write_files:
- path: /etc/motd
content: |
Web Server - Managed by Proxmox
Provisioned via cloud-init
EOF
Attach the snippet to your VM:
qm set 101 --cicustom "user=local:snippets/web-server-init.yml"
Automating Deployment with Scripts
Combine cloud-init templates with a simple bash script for rapid, repeatable deployments:
#!/bin/bash
TEMPLATE_ID=9000
START_ID=200
COUNT=3
BASE_IP="10.0.0"
for i in $(seq 1 $COUNT); do
VMID=$((START_ID + i))
IP="${BASE_IP}.$((200 + i))"
qm clone $TEMPLATE_ID $VMID --name "worker-node-${i}" --full
qm set $VMID --ipconfig0 "ip=${IP}/24,gw=${BASE_IP}.1"
qm set $VMID --cores 4 --memory 4096
qm start $VMID
echo "Created and started worker-node-${i} with IP ${IP}"
done
This script creates three worker VMs, each with a unique IP address, in under a minute. Combined with the Proxmox API, you can build even more sophisticated provisioning workflows triggered by external systems.
Once your cloud-init templates are in place, you can verify that cloned VMs boot correctly and receive the right configuration even while away from your desk. ProxmoxR makes it easy to check the status of newly deployed VMs from your phone — confirm they are running, verify their resource allocation, and catch any failed starts immediately.
Best Practices
- Version your templates: Name templates with dates or version numbers (e.g.,
ubuntu-2404-v3) so you know which base image they use. - Keep templates minimal: Do not install too many packages in the template itself. Use cloud-init snippets for role-specific customization.
- Use full clones for production: Linked clones save storage but create a dependency on the template disk. Full clones are safer for important workloads.
- Regenerate machine-id: Cloud images typically handle this automatically, but verify that
/etc/machine-idis unique across clones. - Test templates regularly: Cloud images are updated frequently. Rebuild your templates periodically to include the latest security patches.
Summary
Cloud-init templates transform Proxmox VE from a manual virtualization platform into an automated deployment engine. By combining cloud images with Proxmox's template and cloning system, you can provision fully configured VMs in seconds rather than minutes. Whether you are deploying a single test server or spinning up an entire cluster of worker nodes, cloud-init templates make the process fast, consistent, and repeatable.
Take Proxmox management mobile
All the features discussed in this guide — accessible from your phone with ProxmoxR. Real-time monitoring, power control, firewall management, and more.