ESC

Start typing to search across invoices, services, domains, tickets, and more...

Search... Ctrl+K
Virtualization & Host Nodes

Create a Cloud-Init Template in Proxmox VE: Import Debian/Ubuntu Cloud Images and Clone VPS Fast

5 steps 14 min read 1 views 0
On this page

If you provision customer VPS on a dedicated server with Proxmox VE, installing every guest from an ISO is slow and error-prone. A Proxmox VE cloud-init template is far more efficient: import the official Debian or Ubuntu cloud image, attach a cloud-init drive, convert it to a template, and every new VPS becomes a clone plus IP, SSH key and password, delivered in under a minute. This guide applies to Proxmox VE 7.x/8.x; run all commands as root on the host.

The examples use template ID 9000, VM storage local-lvm, public bridge vmbr0 and the documentation range 203.0.113.0/24. Replace them with the IP block and gateway IMIDC assigned to you. See the guide "Assign IPs to Proxmox VMs" for more on public addressing.

Step 1: Download the Official Debian / Ubuntu Cloud Image

Cloud images are minimal system disks built by the distributions for cloud platforms, with cloud-init preinstalled to pick up hostname, user, SSH keys and network on first boot. For Debian use the genericcloud build (small, KVM-oriented); for Ubuntu use server-cloudimg. Optionally preinstall qemu-guest-agent with virt-customize so Proxmox can read guest IPs and shut down cleanly.

cd /var/lib/vz/template/iso   # any directory with enough space
# Debian 12 (bookworm) generic cloud image
wget https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.qcow2
# Ubuntu 24.04 LTS (noble) cloud image
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

# optional: preinstall qemu-guest-agent into the image
apt install -y libguestfs-tools
virt-customize -a debian-12-genericcloud-amd64.qcow2 --install qemu-guest-agent

Step 2: qm create the VM and Import the Cloud Image with importdisk

Create an empty VM without a disk, import the cloud image as its disk, then attach it as scsi0 and make it the boot device. Proxmox converts the image to the target storage format during import.

qm create 9000 --name debian12-cloudinit --memory 2048 --cores 2 \
  --cpu host --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci --ostype l26

# import the image as a disk of VM 9000 on storage local-lvm
qm importdisk 9000 debian-12-genericcloud-amd64.qcow2 local-lvm
# (PVE 8 also accepts: qm disk import 9000 debian-12-genericcloud-amd64.qcow2 local-lvm)

qm set 9000 --scsi0 local-lvm:vm-9000-disk-0,discard=on
qm set 9000 --boot order=scsi0
Use the disk name printed by the import (usually vm-9000-disk-0). On directory storage such as local, the name looks like 9000/vm-9000-disk-0.raw instead; adjust accordingly.

Step 3: Add the Cloud-Init Drive and Set User, SSH Keys and IP

The cloud-init drive is a virtual CD where Proxmox writes the settings from the Cloud-Init tab. Cloud images usually need a serial console to display properly in the web Console, so set serial0 too. User and key set on the template act as defaults and can be overridden on each clone.

qm set 9000 --ide2 local-lvm:cloudinit
qm set 9000 --serial0 socket --vga serial0
qm set 9000 --agent enabled=1

# defaults stored in the template (can be overridden per clone)
qm set 9000 --ciuser debian --sshkeys /root/.ssh/id_ed25519.pub
qm set 9000 --ipconfig0 ip=dhcp
qm set 9000 --nameserver "1.1.1.1 8.8.8.8"
qm cloudinit dump 9000 user

The last command previews the generated user-data so you can confirm the username and key are included.

Step 4: Convert the VM into a Cloud-Init Template

Do not boot the VM; convert it straight away. A template cannot be started, only cloned, and its disk becomes a read-only base image.

qm template 9000
qm list

Step 5: Clone VPS Fast from the Template and Inject IP and SSH Keys

There are two kinds of clone. A full clone (--full) copies an independent disk and is right for customer delivery. A linked clone is nearly instant and saves space but depends on the template's base disk (the template can no longer be deleted), so it suits internal testing. Give each VPS its own IP, key or initial password and grow the disk as needed; the cloud image is only 2–3 GB and cloud-init expands the partition on first boot.

# full clone (independent disk) for a customer VPS
qm clone 9000 201 --name vps201 --full --storage local-lvm

# or a linked clone: created in seconds, shares the base disk
# qm clone 9000 202 --name vps202

qm set 201 --cores 2 --memory 4096
qm set 201 --ipconfig0 ip=203.0.113.21/24,gw=203.0.113.1
qm set 201 --sshkeys /root/customer201.pub --cipassword 'Change-Me-123'
qm resize 201 scsi0 +38G
qm start 201

# check
qm guest cmd 201 network-get-interfaces
ssh [email protected]

For bulk provisioning, wrap the steps in a small script that takes the VM ID, IP and customer key:

#!/bin/bash
# usage: ./newvps.sh 205 203.0.113.25 /root/keys/c205.pub
ID=$1; IP=$2; KEY=$3
qm clone 9000 "$ID" --name "vps$ID" --full --storage local-lvm
qm set "$ID" --ipconfig0 ip="$IP"/24,gw=203.0.113.1 --sshkeys "$KEY"
qm resize "$ID" scsi0 +38G
qm start "$ID"

In the web UI: right-click the template → Clone → mode "Full Clone", then edit IP Config and SSH public key on the new VM's Cloud-Init tab, click "Regenerate Image" and start it.

FAQ

I cannot SSH into a cloned VPS

Check that ipconfig0 matches the IP, mask and gateway IMIDC assigned; log in as the ciuser (debian by default on Debian, ubuntu on Ubuntu), not root; and reboot the VM after changing Cloud-Init settings. The serial Console in Proxmox shows the cloud-init boot log for troubleshooting.

The disk still shows 2 GB after resizing

Run qm resize before the first boot so cloud-init's growpart expands the root partition. If the VM already booted, run growpart /dev/sda 1 and resize2fs /dev/sda1 inside it (check partition names with lsblk).

Can I use CentOS / Rocky / AlmaLinux cloud images?

Yes. Rocky Linux and AlmaLinux publish GenericCloud qcow2 images; the procedure is identical, with default users rocky and almalinux respectively.

Still stuck? Open a ticket with IMIDC 24/7 technical support: https://www.imidc.com/submitticket.php

Was this answer helpful?

Related Tutorials