# 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] [args] Commands: list [distro] List available distros, cached images, and VM templates download [ver] Download image into cache only (no VM, no modifications). Use "all" to download every supported distro. create [ver] Download cloud image (if needed) and create VM template update [ver] Re-download and re-create a template (remove + create) remove [ver] Remove cached image and VM template for a distro Options: -d, --dir DIR Image cache directory (default: /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 ```bash # 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 ```bash # Clone the template — repeat for as many VMs as you need qm clone --name my-vm --full # Or with a specific target storage qm clone --name my-vm --full --storage local-btrfs ``` ## Customizing Cloud-Init Per-VM After cloning, edit the clone's cloud-init config: ```bash qm set --ciuser myuser --sshkeys ~/.ssh/id_rsa.pub qm set --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1 qm set --nameserver 1.1.1.1 qm set --searchdomain example.com qm start ``` ## 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`: ```bash ./pve-cloudimg.sh create ubuntu --packages "htop nfs-common" ``` **Per-distro** by adding entries right under each `DISTROS` definition in the script: ```bash 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: ```bash # 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: ```bash 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 `/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