RemarkableCloud

Proxmox Templates: The Ultimate Guide

How to create reusable Proxmox cloud-init VM templates for fast server provisioning on RemarkableCloud infrastructure.

Proxmox templates let you provision new VMs in seconds by cloning a pre-configured base image. Combined with cloud-init, each clone boots with a unique hostname, SSH key, and IP configuration automatically.

What is a cloud-init template?

A cloud-init template is a VM that has been:

  1. Installed with a minimal OS
  2. Cleaned of unique identifiers (SSH host keys, machine ID)
  3. Configured with cloud-init to accept per-clone configuration
  4. Converted to a Proxmox template (made non-bootable as a standalone VM)

When you clone it, cloud-init applies the hostname, SSH keys, and network config on first boot.

Creating a template (AlmaLinux 9 example)

Step 1: Download the cloud image

# On your Proxmox host
cd /var/lib/vz/template/iso

wget https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2

Step 2: Create the VM

# Create a VM with ID 9000
qm create 9000   --name "almalinux-9-template"   --memory 2048   --cores 2   --net0 virtio,bridge=vmbr0   --ostype l26   --agent enabled=1

# Import the cloud image as disk
qm importdisk 9000 AlmaLinux-9-GenericCloud-latest.x86_64.qcow2 local-lvm

# Attach disk as primary drive
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0

# Add cloud-init drive
qm set 9000 --ide2 local-lvm:cloudinit

# Set boot order
qm set 9000 --boot c --bootdisk scsi0

# Add serial console (required for cloud images)
qm set 9000 --serial0 socket --vga serial0

Step 3: Configure cloud-init defaults

qm set 9000   --ciuser root   --cipassword "$(openssl passwd -6 'changeme')"   --sshkeys /root/.ssh/authorized_keys   --ipconfig0 ip=dhcp   --nameserver "8.8.8.8 1.1.1.1"

Step 4: Convert to template

qm template 9000

The VM is now a template. It cannot be started directly: only cloned.

Cloning and deploying a new server

# Clone the template to VM ID 101 with a new disk
qm clone 9000 101   --name "web-server-01"   --full   --storage local-lvm

# Set VM-specific cloud-init values
qm set 101   --ipconfig0 ip=10.0.0.10/24,gw=10.0.0.1   --ciuser root   --hostname web-server-01.yourdomain.com

# Resize disk (optional: expand from template default)
qm resize 101 scsi0 +20G

# Start the VM
qm start 101

The VM boots, cloud-init runs, and within 30-60 seconds it’s accessible via SSH at the configured IP.

Automating with a script

#!/bin/bash
# Usage: ./deploy.sh <vmid> <hostname> <ip> <gateway>
VMID=$1
HOSTNAME=$2
IP=$3
GW=$4
TEMPLATE=9000

qm clone $TEMPLATE $VMID --name "$HOSTNAME" --full --storage local-lvm
qm set $VMID --ipconfig0 ip=$IP/24,gw=$GW --hostname $HOSTNAME
qm resize $VMID scsi0 +10G
qm start $VMID
echo "VM $VMID ($HOSTNAME) starting at $IP"

Maintaining templates

Update your template periodically by:

  1. Cloning the template to a temporary VM
  2. Starting it and running OS updates (dnf update -y)
  3. Running cloud-init cleanup: cloud-init clean --logs
  4. Shutting down the VM
  5. Converting back to template: qm template TMPVMID
  6. Deleting the old template and renaming the new one
Take a snapshot of the updated VM before converting to template, in case the update introduces issues and you need to roll back.
Still stuck? Ask a human, we answer in minutes.