Files
scripts/proxmox-cloudimg/README.md
T

8.0 KiB

Proxmox Cloud Image Manager

Download, customize, and create VM templates from cloud images for popular Linux distributions. Enables fast VM deployment with cloud-init — just like a real cloud provider.

Requirements

  • Proxmox VE host (script auto-elevates with sudo if needed)
  • Packages: curl, qemu-utils, libguestfs-tools (optional, for qemu-guest-agent injection)

Usage

Usage: pve-cloudimg.sh [options] <command> [args]

Commands:
  list [distro]           List available distros, cached images, and VM templates
  download <distro> [ver] Download image into cache only (no VM, no modifications).
                           Use "all" to download every supported distro.
  create <distro> [ver]   Download cloud image (if needed) and create VM template
  update <distro> [ver]   Re-download and re-create a template (remove + create)
  remove <distro> [ver]   Remove cached image and VM template for a distro

Options:
  -d, --dir DIR           Image cache directory (default: <script-dir>/cloud-images/; set \$PVE_CLOUDIMG_DIR to change default)
  --storage STORAGE       Proxmox storage for VM disks (default: main-storage)
  --bridge BRIDGE         Network bridge (default: vmbr0)
  --vlan VLAN             VLAN tag for the network interface
  --bios BIOS             Firmware: seabios (default) or ovmf (UEFI)
  --vm-id VMID            VM ID for the template (default: auto from 9000)
  --cores CORES           CPU cores (default: 2)
  --memory MEMORY         Memory in MB (default: 2048)
  --disk-size SIZE        Disk size in GB (default: 10)
  --user USER             Cloud-init default user (default: distro-specific)
  --ssh-key FILE          SSH public key file to inject via cloud-init
  --no-agent              Skip installing qemu-guest-agent
  --packages PKGS         Extra packages to install (comma/space-separated, passed to virt-customize)
  -f, --force             Re-download image even if already cached
  -y, --yes               Skip confirmation prompts

Examples

# List available distros, cached images, and templates
./pve-cloudimg.sh list

# Pre-cache an image (download only, no modifications)
./pve-cloudimg.sh download debian

# Pre-cache every supported distro
./pve-cloudimg.sh download all

# Create a template from the default distro version (Ubuntu 26.04)
./pve-cloudimg.sh create ubuntu

# Create from a specific version with custom settings
./pve-cloudimg.sh create ubuntu 24.04 --storage local-btrfs --disk-size 64 --ssh-key ~/.ssh/id_rsa.pub

# Create with custom user and resources
./pve-cloudimg.sh create debian --user admin --cores 4 --memory 8192 --bridge vmbr1

# Create on a specific VLAN
./pve-cloudimg.sh create ubuntu --vlan 100

# Install extra packages alongside the guest agent
./pve-cloudimg.sh create ubuntu --packages "htop nfs-common"

# Live dangerously — Arch Linux rolling release
./pve-cloudimg.sh create arch

# Force re-download even if cached (adds --force to any command)
./pve-cloudimg.sh download ubuntu --force
./pve-cloudimg.sh create ubuntu --force

# Update to the latest image (re-download and re-create template)
./pve-cloudimg.sh update ubuntu

# Replace an existing template with a completely different distro
./pve-cloudimg.sh remove ubuntu
./pve-cloudimg.sh create debian

# Remove a template and its cached image
./pve-cloudimg.sh remove ubuntu 24.04

Supported Distributions

Distro Default Versions Default User
Ubuntu 26.04 26.04, 24.04 ubuntu
Debian 13 13, 12 debian
Arch Linux rolling rolling arch

How It Works

  1. Download (download command) — Fetches the official cloud image from the distro's mirrors and caches it locally. No modifications.
  2. Resize (create command only) — Expands the disk to the requested size on a working copy (cloud-init's growpart resizes the partition on first boot)
  3. First-boot script (create command only) — Writes a systemd oneshot service via virt-customize that installs packages (qemu-guest-agent + any extras) on first boot of each cloned VM
  4. Create VM (create command only) — Configures CPU, memory, VirtIO SCSI controller, serial console, and QEMU guest agent
  5. Cloud-Init (create command only) — Sets default user, optional SSH key, and DHCP networking
  6. Template (create command only) — Converts the VM to a Proxmox template ready for cloning

Use download to just fetch and cache the image without any modifications. Use create for the full pipeline (resize + firstboot installer + import + template).

Deploying a VM from a Template

# Clone the template — repeat for as many VMs as you need
qm clone <template-vmid> <new-vmid> --name my-vm --full

# Or with a specific target storage
qm clone <template-vmid> <new-vmid> --name my-vm --full --storage local-btrfs

Customizing Cloud-Init Per-VM

After cloning, edit the clone's cloud-init config:

qm set <new-vmid> --ciuser myuser --sshkeys ~/.ssh/id_rsa.pub
qm set <new-vmid> --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1
qm set <new-vmid> --nameserver 1.1.1.1
qm set <new-vmid> --searchdomain example.com
qm start <new-vmid>

QEMU Guest Agent

Rather than installing packages inside a chroot during image preparation (which breaks on many distros due to Landlock, missing dnf, incompatible arch detection, etc.), the create command writes a first-boot installer into the working copy via virt-customize --firstboot-command. This creates a systemd oneshot service that runs on the first boot of each cloned VM:

Distro family Runs on first boot
Ubuntu, Debian apt-get update && apt-get install -y qemu-guest-agent
Arch Linux pacman -S --noconfirm qemu-guest-agent

The installer runs in the actual VM environment with full kernel support, network access, and proper repos — no chroot limitations.

The download command does not apply any first-boot scripts — it only fetches and caches the raw cloud image.

To skip agent installation: --no-agent

Installing Extra Packages

Two ways to add packages beyond qemu-guest-agent:

Per-run with --packages:

./pve-cloudimg.sh create ubuntu --packages "htop nfs-common"

Per-distro by adding entries right under each DISTROS definition in the script:

DISTROS["ubuntu:26.04"]="..."
DISTRO_PACKAGES["ubuntu:26.04"]="htop nfs-common"

Packages with different names across distros get their own DISTRO_PACKAGES entry.

Adding a New Distribution

Edit pve-cloudimg.sh and add entries near the top of the file. Each distro gets one or more DISTROS lines, with an optional DISTRO_PACKAGES line directly below:

# Image definition
DISTROS["mydistro:1.0"]="https://example.com/image.qcow2|filename.qcow2|default-user|qcow2"
# Extra packages (optional, right below its DISTROS entry)
DISTRO_PACKAGES["mydistro:1.0"]="my-package other-package"

The DISTROS format is: url|filename|default_user|image_format

Then add a default version so create mydistro (without a version) works:

DISTRO_DEFAULT_VERSION[mydistro]="1.0"

Notes

  • Run on the Proxmox host — the script auto-elevates with sudo if not run as root
  • Images are cached in <script-dir>/cloud-images/ by default — override with -d or $PVE_CLOUDIMG_DIR
  • If you add the script to PATH (e.g. /usr/local/bin/), set PVE_CLOUDIMG_DIR=/var/cache/proxmox-cloudimg in your shell rc so it doesn't try to write into /usr/local/bin/cloud-images/
  • The script auto-increments VM IDs starting at 9000
  • Cloud images from official distro mirrors — always up to date
  • Use -f/--force to re-download an image even if already cached (e.g., to refresh a stale image)
  • Resized disks use cloud-init's built-in growpart for automatic partition resizing on first boot
  • Templates, clones, and cached images are independent — removing a template or cached image does not affect running VMs cloned from it
  • To replace a template with a different distro, remove the old one then create the new one — they get separate VM IDs