Cloud-Init Templates
One-click cloud-image templates. Pick a curated upstream image (Ubuntu, Debian, Rocky Linux, AlmaLinux, Fedora, Alpine), pick a target node + storage, and PegaProx downloads the qcow2 / raw, runs qm importdisk, sets the cloud-init drive, and converts it to a template. No shell, no wget /tmp/... dance.
Curated images
The library is shipped with a vetted list of upstream cloud-images (URL + SHA256 + recommended config). Library entries are refreshed on update; from 1.3 a weekly CI job checks that every catalog URL still answers.
- Ubuntu 22.04 / 24.04 / 26.04 LTS
- Debian 12 / 13
- Rocky Linux 9 / 10
- AlmaLinux 9 / 10
- Fedora Cloud Base 44
- Alpine 3.24
The Enterprise Linux 10 images need a newer CPU model; the catalog passes the model they need (x86-64-v3). The image ids fedora-40, debian-11 and alpine-319 were removed in 1.3; a custom template or script that names them needs a current id.
Custom Templates
Paste your own http / https image URL. The same import flow runs - you get a template at the end. Useful for golden images, in-house base OS builds, or air-gapped registries (host the image on an http:// endpoint behind your own auth). From 1.3, a login written into the URL (https://user:password@host/...) is used for the download but shown as **** in the catalog and the deployment log.
Audit
The "Recent Deployments" widget shows who deployed what, when. Failed deployments include the full Proxmox task log line that broke. Audit-log entry includes the image URL + checksum.
Security
This was the C-1 finding from the v0.9.9 security audit and is now hardened:
- Custom image URLs are parsed via
urllib.parse- onlyhttp/httpsschemes are accepted (the deploy runswgeton the node, sofile://,ftp://, etc. are rejected). - The URL is additionally rejected if it contains shell-hostile characters (space,
;|&`$, quotes, backslash, newline, tab). node,storageand VM name are validated against a^[A-Za-z0-9._-]+$regex whitelist before dispatch.- Every shell-bound argument in the
qm/wgetcommands is wrapped inshlex.quote().
API
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/templates/catalog |
Curated CATALOG + user-defined custom templates |
POST |
/api/templates/custom |
Add a custom template (perm: vm.create). Body: {name, image_url, cores?, memory?, disk_gb?, distro?, version?, default_user?, tags?} |
DELETE |
/api/templates/custom/{tpl_id} |
Delete a custom template (perm: vm.create) |
POST |
/api/clusters/{cluster_id}/templates/deploy |
Kick off async deploy (perm: vm.create). Body: {template_id, node, storage, vmid?, name?} |
GET |
/api/clusters/{cluster_id}/templates/deployments |
Recent deployments for a cluster, newest first (perm: cluster.view) |
GET |
/api/templates/deployments/{dep_id} |
Detailed deployment status incl. log tail (perm: cluster.view) |
GET |
/api/clusters/{cluster_id}/templates/existing |
Existing template VMs on the cluster (perm: cluster.view) |