github PegaProx/project-pegaprox v1.5.0
PegaProx 1.5.0

one hour ago

PegaProx 1.5.0 brings Corporate Redesigned, a second corporate layout each user can switch to, VM blueprints that keep a VM's hardware and Cloud-Init settings once and deploy them to any Proxmox VE cluster, a QDevice for 2-node clusters that PegaProx sets up against a QNetd host once you agreed to its plan, ESXi migrations with a network per NIC, a storage per disk, a review step, a full disk check and bulk runs, a lock an admin can put on the layout and the language, custom node hardening profiles, Russian as the tenth UI language, and full-database encryption on more platforms. Rolling updates now wait for proof that a node really restarted, failed Proxmox reads show as errors instead of empty lists or green tiles, and a long list of security fixes closes issues reported to us privately and found in our own reviews.

Please read the behaviour changes before updating, and take a backup first. Updating is recommended for every install: several of the security fixes concern 1.4.1 and older. The changes most likely to bite:

  • The first start encrypts the database on the Debian package, on pip and deploy.sh installs on aarch64 Linux, macOS and Windows, and in the arm64 Docker image. After that, 1.4.1 without SQLCipher cannot open it.
  • Portal-only accounts are held to the Client Portal by the server, and accounts confined to some guests see only the nodes their guests run on.
  • Failed Proxmox reads answer 502 or 503 where API clients used to get 200 with an empty list, and HTTP redirects are no longer followed by the Proxmox VE, PBS and ESXi connections.

The in-app update and update.sh install the new requirements by themselves. Docker users get them with the new image; Debian and appliance users run apt update && apt upgrade.

🔒 Security

Issues reported to us privately and found in our own reviews.

  • A new container needs a root password or an SSH key. Creating one through the API without either now answers 400, and with only a key no password is set; before, every container created through the API without a password got a fixed root password, also when an SSH key was given. The Create Container wizard of Modern and both Corporate layouts keeps Create disabled until one is filled in. Containers that an earlier version created through the API without a root password (also when an SSH key was given), and their clones, templates and backups, should get a new root password.
  • Accounts confined to some guests by a pool grant or a VM ACL see only the nodes their guests run on, in metrics, node lists, live streams, topology, search, health, maintenance and update reads (#1218). Host and datacenter reads are refused to them (node disks, SMART, LVM and ZFS, network config, sensors, hardware, certificates, subscription key, the datacenter firewall, SDN, cluster and join info, PCI and USB mappings, HA groups, config export, the cluster-wide storage and Ceph reads), and /networks, the HA status, the what-if picker and reports and the capacity forecast show them only their own part, including just the backup jobs that name their own guests and the nodes their guests run on in a PBS report. Placing a guest keeps to their nodes. The node summary, its charts and the bridge, ISO and device lists of the guest dialogs stay readable where one of their guests runs.
  • Backup servers: an account confined to some guests by a pool grant or a VM ACL, on any cluster a PBS backs up, no longer reads the PBS server itself. Its status, syslog, network, DNS, time, disks and SMART, jobs, remotes, subscription, traffic control, datastore settings and charts, updates, health and capacity forecast answer 403. The account still browses its own guests' backups: the datastore list gives only the names, the namespace list only the paths, and the server list leaves out the live figures.
  • Affinity rules: an account confined to some guests sees only the affinity rules whose guests it may all see, on /api/affinity-rules as on the cluster route. The affinity check and a blocked migration name the rule but not its other guests or their node. A rule without a cluster is listed to administrators only.
  • Portal-only accounts are held to the Client Portal by the server, not only by the UI: sign-in, session, SSO, their 2FA enrolment, the portal API and the portal console work, and every other API route, stream and console answers 403 PORTAL_ONLY, also for their API tokens. Per guest they get what an ACL row or a pool grant names, never the role-wide grant. Administrators are never held.
  • The Client Portal's ISO routes follow the hoster's allow_iso_mount switch and accept only the CD-ROM slots ide0 to ide3 and sata0 to sata5 as the drive.
  • Node shell: the route that hands cluster credentials to the console server answers only PegaProx's own console server (403 CONSOLE_SERVER_ONLY for a browser session), opening a node shell no longer hands the browser the cluster account's Proxmox cookie, and on a cluster with SSH switched off the node shell no longer opens.
  • No redirects: the Proxmox VE, PBS and ESXi connections, the storage preflight, the console logins and the websocket upgrades no longer follow a 3xx answer, so a redirect cannot carry a call or a login to another host or down to plain http. Webhook and ntfy alerts that get a redirect count as not delivered.
  • ESXi migrations: disk file names with control characters, quotes, backticks, $, backslashes or a slash are refused (a comma too in the modes that can end in Live Mirror), and every place such a name reaches a shell quotes it. The ESXi password is kept off command lines on the Proxmox node while a copy runs, and the task log masks an HTTP Basic login.
  • A stored secret stays with the server it was typed for: moving the SMTP or LDAP server (host or port), a SIEM endpoint, the URL or fingerprint of an SDN IPAM or PowerDNS entry, or an address in a plugin config while its secret stays masked is refused with CREDENTIAL_REQUIRED.
  • Masked on the way out: the SDN IPAM and DNS lists drop the NetBox or phpIPAM token and the PowerDNS key; plugin configs (the ntfy token, Apprise URLs, the status page key and every value under a key named like a credential) show masked, keep the stored value on save, and their config.json is written for its owner only; alert channel URLs show only scheme://host/... in the channel list, the server settings and the support bundle; SIEM headers with key-like names show masked; the XAPI session id of XCP-ng requests stays out of task errors, logs and the support bundle.
  • The notifications plugin shipped with ntfy on and the topic pegaprox-test on ntfy.sh, where anyone can subscribe to a topic. The shipped config has ntfy off and no topic now, and an install still holding that pair without a token counts as not configured.
  • SSO sign-in refuses an ID token whose signature, audience, authorized party, issuer, validity window or nonce does not check out; before, a token that failed its check was read unchecked. Tokens signed with RS, PS or ES at 256, 384 or 512 bits or with EdDSA are verified, also from key sets without key ids, and the token, userinfo and Graph requests of a sign-in follow no redirect.
  • Secrets in logs and exports: the audit log, the task log and the support bundle show a secret config value, a cloud-init password and the login in a download URL as ***, also in rows written before the update. A settings export without secrets leaves out the LDAP, OIDC and push keys and the alert channels, and the server settings read leaves out the push keypair.
  • Restores keep a stored secret, such as a cluster's credentials, the HA agent key or a fence password, only while the backup leaves its server or cluster address as it is, and the results list every secret to enter again and why.
  • Alerts: an account confined in a cluster sees only the rules of its own guests there and cannot create, change or delete rules in it. Push messages and the push inbox carry only alerts the subscriber may read, node alerts and node rules need node.view, and alerts of the HA group reach only subscribers who see every cluster.
  • Clusters and pools: changing the order of clusters checks access to each of them, and a cluster's pool permission list answers a scoped account for its own pools only.
  • Audit: no new account can take a name the background jobs write audit entries under, and an account's audit scope no longer counts those entries as its own.
  • Audit trail of a deleted cluster: deleting a cluster keeps its audit entries. Since 1.4.0 they were removed with the cluster, and the integrity check of the hash-chained audit log reported them as missing.
  • Plugins: a plugin config.json written by the editor stays readable by its owner only, and the editor opens config files only at the depth a plugin uses.
  • ACME: a downloaded certificate replaces the served one only as a complete chain for this host's key and name, so a download cut short or answered by a proxy page no longer goes live.
  • HTTP redirect: X-Forwarded-Proto and X-Forwarded-Port are taken only from a trusted proxy.
  • Names in cluster API calls: the arguments of the cluster and PBS routes (node, storage, snapshot, interface and the like) are checked before the route runs, and a value holding %, ?, #, a backslash or a control character answers 400 with nothing sent to the cluster. Before, a doubly encoded slash in a node name could turn a call into a different Proxmox VE API path, sent with the cluster's own login. The Proxmox VE and PBS connections also refuse a URL with a #, the root@pam session used for disks and Ceph checks its paths like the others, and the datastore content, upload and download, backup delete, node ISO list, template download, restore and clone routes take only real node and storage names. A node, storage, guest type or VMID in the query string or the body of a Proxmox VE cluster request is checked the same way, / included, and so are the names a cross-cluster migration, replication, cross-hypervisor move, scheduled task, recovery plan, PBS backup diff or bulk snapshot delete takes. XCP-ng and ESXi host names are not affected.
  • ESXi requests: a VM or snapshot id holding ?, # or a . or .. segment is refused before it reaches the ESXi host. Before, such an id could turn the delete of one snapshot into the delete of the VM, for an account allowed to delete snapshots only.
  • OIDC sign-in binding: an OIDC or Entra ID account stays with the identity provider subject it is bound to in the Automatic username mode as well, not only with a picked username claim, so a second person at the identity provider with the same name, an email the provider marks as not verified, or a name that only folds onto the account's (an invisible character, a look-alike letter) no longer takes the account and its role. An account without a subject is bound by the next sign-in whose name is exactly its key, and an admin can reset a binding in User Management. When a sign-in went through without a checked ID token signature, its audit entry says so. The Client Portal's SSO button and the authorize answer follow an https sign-in URL only.
  • LDAP: the LDAP settings take the CA certificate of the directory, so the certificate check works with an internal CA, and new setups start with STARTTLS and the check on. With the check on, PegaProx no longer follows a directory's referrals, which would have reached the referred server without it. The LDAP tab shows a note while the saved settings send passwords in plain text or unchecked, Test Connection names the transport, and a refused certificate points to the CA field instead of telling you to turn the check off. A sign-in, its group search, Test Connection and the password check before a sensitive action count a bind only when the directory accepted it, not just when it returned no error.
  • Node shell: the node shell server trusts a new SSH host key only when it can store it, as the rest of PegaProx does since 1.4.0, and writes known_hosts through a temporary file.
  • Audit pages: the audit page, its search, the timeline and the support bundle no longer stall the server on a long audit row; masking an older download row took seconds per read for 100 KB of details.
  • Client Portal: guest, ISO and snapshot names with quotes, backslashes or line breaks show as written, and the portal buttons act on exactly that name. Before, such a name (an XCP-ng guest name is free text) could end the HTML attribute or the button's script string and run as script in a portal customer's browser. The logo URL, the search box and the destroy confirmation handle quotes as well.
  • Smaller: an account confined to some guests can no longer read, change or test a node's BMC endpoint (removing one was refused already), and only administrators no tenant or cluster list limits switch in-band and Redfish hardware monitoring on or off; the task log masks a mirror login whose password holds both a blank and an @; deleting an IP set entry of a guest firewall sends the entry as one path segment; the release link of the update check and the update mail is always an https page, and the Open GitHub Release link and the ESXi console button open only https pages (the console also vmrc:// links); the node link suffix (node_ui_suffix) takes only a domain name; --migrate-db creates the encrypted copy with mode 0600; new key files are synced to disk before the database depends on them; a scheduled task's backup storage is checked as a storage name before it is stored.

✨ New

  • Corporate Redesigned, a second corporate layout, opt-in per user in My Profile and offered at the first login. It draws its own views over the same data: dashboard, datacenter, alerts and task center, datastores with storage balancing, restore tests, backup SLA and ISO sync, compliance and drift, hardening, reports, what-if and capacity, updates, blueprints, the guest view and VM configuration, and the node pages including disks and network, with a summary of the network changes before Apply. A read that failed or was refused says so, and changes go through the same requests as in the classic views. Corporate Redesigned changes nothing in the other layouts.
  • QDevice for 2-node clusters: PegaProx sets up the corosync QDevice of a 2-node or other even-sized Proxmox VE cluster against a QNetd host. Add the QNetd host once under Settings > High Availability: this PegaProx host (a root-owned helper behind a systemd socket, no sudo rule), any Linux host over SSH such as the witness host, or a Docker sidecar started with docker compose --profile qdevice. Corosync-qnetd and the NSS tools are installed with apt, dnf, yum or zypper, and a corosync-qnetd PegaProx installed requires TLS from the nodes. Set up QDevice on a cluster lists every change by where it happens and starts only after you agreed to that plan for that cluster; the server refuses a setup without that agreement and stops before any change when the plan differs at start. It does what pvecm qdevice setup does, but PegaProx carries the certificates itself, so no node needs a login on the QNetd host, the CA key never leaves the QNetd host, and pvecm qdevice remove keeps working. The preflight refuses an odd node count, an offline node or a cluster without quorum, a QNetd host that is a node or a guest of that cluster, a QNetd port a node cannot reach, and a cluster name the QNetd host serves already. Options install corosync-qdevice on the nodes and open the QNetd port with ufw or firewalld for the node addresses only (removing the QDevice takes out only PegaProx's own rules). Several clusters can be set up on one QNetd host in one run, a new alert rule reports a QNetd host that is down, even-sized clusters without a QDevice show a notice, and a rolling update held for its quorum offers Set up QDevice. Administrators only; see docs/qdevice.md.
  • Classic Corporate is deprecated and only gets fixes from now on. The first-login choice, My Profile and the interface lock offer Modern, Corporate Redesigned and Cloud. Classic Corporate is shown there only to an account still on it, and in the lock only while it is pinned. A bar under its header says so with Switch now and Dismiss (not under an admin's Corporate lock), and nobody is moved automatically.
  • VM blueprints (#1220): a blueprint points at a template library image or at an existing Proxmox VE template (Windows included) and keeps cores, memory, disk size, CPU type, up to four NICs and the Cloud-Init user, SSH keys, IP mode, DNS and tags, but no password. A deploy to any Proxmox VE cluster, node and storage clones or builds the template there, applies the settings, grows the boot disk, can start the VM, and runs as a job with steps and a log. The deploy dialog names the SSH keys that go into the VM. A template blueprint needs a template with a Cloud-Init drive. A Windows blueprint keeps neither the Cloud-Init user, SSH keys nor search domains, and each deploy asks for its administrator password.
  • Blueprints are in Corporate Redesigned (Blueprints & Images), Modern (Automation > Blueprints & Templates) and Cloud (Blueprints & Templates); classic Corporate keeps the template library alone. Deploying needs vm.create, and an account confined to its own guests by a pool grant or a VM ACL cannot deploy. Only the creator or an admin changes a blueprint, the tenant's VMID range and quota apply, and a blueprint is seen only in the tenant of the account that saved it (an admin's in every tenant). Windows blueprints need qemu-server 8.2.4 on the node.
  • Interface lock (#1189, #1167): under Settings > Server > Interface defaults an admin can pin the layout and the language for everyone. An account the lock binds opens in the pinned layout, cannot save another layout or language (403 UI_LOCKED) and gets its own choice back when the lock is lifted. Admins are exempt unless the lock includes them. Off by default; a Corporate lock means classic Corporate, and Corporate Redesigned can be pinned on its own. Changing the lock needs admin.settings on an account no tenant or cluster list limits.
  • Custom node hardening profiles: a named pick of the built-in controls with values for their parameters, never a command of its own. The Harden tab creates, edits, duplicates, exports, imports and deletes them and can save a check selection as one, and the compliance dashboard scores a custom profile over its own controls. Writing needs node.maintenance and admin.settings on an account no tenant or cluster list limits; Proxmox VE nodes only.
  • Russian is the tenth UI language, in the language switcher and the interface lock (#1235).
  • A bookmarkable SSO link (#768): GET /api/auth/oidc/login sends the browser straight to the identity provider, for a bookmark or a portal tile. Without a usable OIDC setup it goes to the login page.
  • EVPN prerequisites (#1154): the cross-cluster EVPN form checks every online node of the picked clusters over SSH for PVE 8 or newer, frr, frr-pythontools, the frr service, ifupdown2, the interfaces.d source line, IP forwarding and NTP, and shows what is missing with a fix hint. It needs both sdn.manage and admin.settings, unconfined access to every picked cluster and working SSH, and is not in classic Corporate.
  • Copy as text (#1192) next to Check for Updates puts the pending updates of a cluster on the clipboard as plain text for a change ticket, every node and the backup servers included, also on plain http.
  • Container replicas with root-only feature flags (#457): Proxmox lets only root@pam set feature flags other than nesting when it creates a container, so a cross-cluster replica of such a container never arrived. Creating the job now warns and names the flags, the replication dialogs show it as soon as the container is picked, and a run that fails on exactly this says so.
  • Site Recovery plans show which replication job each guest fails over to, with its schedule and the replica's VMID, and the link can be changed.
  • Ceph counts in the cluster health score (#948): HEALTH_WARN holds the score at 75 at most and HEALTH_ERR at 25, and the Cluster Health card shows the Ceph status. Clusters without Ceph score as before.
  • PBS: the Jobs tab lists push sync jobs with their direction (PBS 3.3 or later, #801), and a PBS that was down when PegaProx started connects again by itself (#1156).
  • The classic Corporate network table of a node shows each interface's comment (#1162).
  • New API routes read the pending changes of a VM and the network changes of a node that wait for Apply (Proxmox VE), both shown in Corporate Redesigned. pegaprox_multi_cluster.py --set-port writes the listen port on a plain or an encrypted database; deploy.sh and the appliance setup use it.

🔐 Database encryption on more platforms (#1226)

  • pip and deploy.sh installs on aarch64 Linux, macOS and Windows and the arm64 Docker image install sqlcipher3 now and encrypt the whole database, as Linux x86_64 already did. 32-bit ARM stays on plain SQLite. Sensitive fields are encrypted with AES-256-GCM on every platform either way.
  • The Debian package depends on python3-sqlcipher3 and sqlcipher. Before every start it puts the database key in /etc/pegaprox/secret.key (0640 root:pegaprox): it keeps an existing key, copies the key of an already encrypted database byte for byte and never makes a second one. config/.pegaprox.key stays and must be kept.
  • The VM and LXC appliance images build python3-sqlcipher3 for their own architecture and run an encrypted database on amd64 and arm64. A release check fails an image whose database is not encrypted: on amd64 that stops the release, an arm64 image that fails its build or the check is left out of it. No key is baked into an image; each copy makes its own at its first start.
  • The first start after the update encrypts a plain database and keeps a plain copy, pegaprox.db.plain.bak.<timestamp>, until a start after one hour. An encrypted database without a working SQLCipher stops the start with [FATAL] [DBCRYPTO] and the reason; a SQLCipher that is installed but does not load is a warning in the log, in --keystore-status and in the Compliance tab.
  • --keystore-status only reads now (it no longer creates a key where it finds none) and lists which databases are encrypted, --print-key prints the key alone for systemd-creds, and the advice for a legacy key says to copy config/.pegaprox.key to /etc/pegaprox/secret.key and keep the old file.

🔁 Rolling updates and maintenance

  • A node counts as back only once it was seen down or its uptime shows it restarted, and a failed or partial status read is no longer taken for a node going down. A node that never restarts fails the update, and so does a reboot that could not be sent, with the reason.
  • The reboot timeout of a rolling update reaches the update task, and Wait until a rebooted node is back, when off, really skips that wait.
  • On XCP-ng a host has to be proven back, or the run holds for Continue or Cancel, and a failed package check no longer counts as up to date.
  • The Ceph gate compares Ceph's check codes and sees every check and every PG state.
  • Scheduled rolling updates run on the same engine as manual ones: they pause on a failed node or an evacuation error, honour the Ceph gate and Wait until a rebooted node is back, and send to their notification channels, with a rolling_update.paused event.
  • An evacuation that could not read its guests, or still has guests after the wait, fails instead of reporting an empty node, and a cancel or a maintenance exit stops it before the next guest.
  • Before a live move PegaProx ejects the ISO from every CD drive on any bus, not only ide2 (#1169).
  • The up-to-date check waits up to 180 s for apt update (#1135), and a node its update task already took out of maintenance no longer logs a failed maintenance exit (#953).

🧱 Failed reads say so

  • Network, time, system log, certificates, tasks, subscription, LVM, LVM-Thin, ZFS, PCI devices, storage content and the Ceph reads answer 502 PVE_READ_FAILED or 503 PVE_UNREACHABLE when Proxmox refuses or does not answer, instead of 200 with an empty list. The datacenter status, the node DNS read (#1163) and the HA resources answer 502 with an error as well, without the PVE_READ_FAILED code (the datacenter status 503 when the cluster is unreachable).
  • The UI says a read failed instead of showing nothing, 0 percent or a green tile: the datacenter summary and overviews, the DNS form (whose inputs stay locked until a read works), the guest HA card, the drift tab, the Balancing tab, the reports, and Ceph, which no longer says it is not installed after a failed read.
  • PBS refusals of GC, verify, prune, snapshot delete and job runs answer 502 with the reason, an rbd mirror action that rbd refused is an error, and a Proxmox task that ended with errors is marked failed (with warnings it counts as done).
  • A snapshot policy that could not read its guest list fails and stays due instead of being stamped as run.

🚚 Migrations

  • ESXi migrations, step by step: pick a bridge and VLAN per NIC and a storage per disk, or leave out NICs and data disks. A review step checks the plan against the target node before anything starts. Verification Full compares every block of each copied disk with its source before the target starts (Live Clone, Auto and Offline Copy). A request without these choices sends the same commands as before.
  • ESXi bulk migration: up to 200 guests of one ESXi server in one run, one to five at a time, with one set of target settings and each guest's own NIC and disk choices. Every guest is checked first and again right before it starts, and each started guest is a normal migration with its switchover gate. The run's ESXi password is held in memory only, and a restart of PegaProx ends the run.
  • With Remove source VM, the ESXi snapshot-iterative, pre-sync and fallback paths and the XCP-ng to Proxmox VE and Proxmox VE to XCP-ng migrations start the target and delete the source only once it runs. A disk that could not be attached fails the migration before anything is started or destroyed, except from ESXi to XCP-ng, where only a failed boot disk does and a data disk that could not be attached stays a warning. An ESXi disk copied only in part fails the migration instead of completing it.
  • For ESXi guests, Firmware Auto gives an EFI guest its efidisk0 (#1268), the migration dialog shows the source's firmware, Secure Boot, TPM and guest OS, and a missing EFI loader is a warning in the result with what to do.
  • IO Thread, cache mode, Discard and SSD emulation from the Advanced tab reach the migrated disks (#1270, #1246), with Discard on by default.
  • A Live Mirror pauses the guest only until QEMU takes the pivot, instead of its full window of about 24 seconds, and the log says how long the guest was paused (#1250). A mirror job that ended before its pivot falls back to the copy.
  • VirtIO driver injection works on Ceph RBD targets (#1245) and also stages the guest agent (#1247), and a snapshot removal over SOAP ends when ESXi is done (#1249).
  • An ESXi to XCP-ng migration attaches its disks and the mapped networks, and XCP-ng to ESXi is refused, since ESXi is a source only.
  • The V2P probe and the ESXi import offer the stored SSH key before a password (#1224).

🐛 Fixes

  • Console: the upgrade to Proxmox sends one Host header, so the console no longer closes right after opening on pveproxy versions that refuse duplicate headers (#1329). The Stable Mode console starts its fallback once and sends in order, and the SSH tunnel waits for a slow browser.
  • SSH: every SSH login PegaProx makes to a Proxmox VE node on its own uses the cluster's SSH user, root when none is set, and the cluster dialog has an SSH user field (#1322). Remove Node, the node shell and node commands use the cluster's SSH port, sensor, cluster health and NIC counter reads use the cluster's SSH key (#601), and a re-configure keeps the settings its form leaves out and can remove a stored key (#1251).
  • Guests and disks: CPU models come from the VM's own cluster; a NIC edit keeps what the dialog does not show; hotplug 1 reads as network, disk and USB; Add Disk refuses a slot in use; Remove Disk with delete data deletes only that volume and only one of that guest; VirtIO Block disks are created without SSD emulation, which Proxmox VE refuses on that bus; Start after creation starts the guest on Proxmox VE; adding a NIC to a container works; the clone dialog's Cloud-Init fields reach the clone; Assign to Pool needs pool.assign, not admin.users (#1238); on the node Disks tab Wipe Disk reaches Proxmox VE (a cluster connected with an API token needs its stored root@pam password for it) and Initialize GPT works on XCP-ng hosts (#1213).
  • Storage: storage totals count each storage once and only storages that take guest disks, so PBS datastores and backup shares no longer add to them (#1159); storage balancing compares only members it could read, moves container volumes, and a deleted group stays deleted; the LVM, LVM-Thin and repository tables read what the node sends.
  • Backups, snapshots, replication: snapshot replications every 15 or 30 minutes run that often; a snapshot policy with both retention rules off, or created with keep 0, keeps its snapshots, and retention waits for each delete; the backup SLA goes by the backup, not the storage name; emptying a backup job field clears it; scheduled backups go to the storage they were given; batch restore suggests a free VMID; cross-cluster migrations, Site Recovery and replication keep their temporary token until their task ends (#1349, #1350); an emergency failover starts the replica under its own VMID.
  • Alerts and accounts: thresholds and intervals that are not numbers are refused and no longer stop the alert loop; password expiry counts from a real date, and its warning mails go out; a later LDAP sign-in takes back a tenant the directory no longer maps, once a sign-in under 1.5 recorded that tenant while the directory still mapped it; audit search accepts admin.audit within the caller's scope; saved OIDC audiences reach the ID token check, and the self-signed TLS switch reaches the token, userinfo and key requests; a passkey request on a bracketed IPv6 address gets the hint to use a host name; SIEM targets send their stored secrets instead of the mask.
  • Hardware and hardening: SEL events get the severity of their level, Redfish reports an opened chassis as critical, a hardening apply counts only when the control ran and its own check passes, audit-only controls show as not applicable, and apply and rollback are audited.
  • XCP-ng: the pool balancer honours dry run, enabled and excluded hosts; the Networks tab lists the pool's networks; an ISO upload to a storage repository sends the pool session; the Tasks tab of a guest lists its tasks.
  • UI: a drag out of a dialog no longer closes it (#1228); a guest picked in All Guests opens in Modern (#1229); the resources list scrolls sideways; the Modern header wraps up to 1880 px so the user menu stays reachable; on phones the drawer closes when a dialog opens from it; sixteen texts show words instead of key names; cluster and storage pickers say what they pick; a tab whose session ended stops asking for stream tokens; the CVE report PDF prints the CVE and its urgency.
  • Client Portal: the Reboot button follows vm.restart (#1239), the SSO button shows when the main window is signed in, and a portal account that opens the main address is sent to /portal (#810).
  • Server: an update rollback restores the files the updater saved, or refuses (#1340); the syslog size cap measures pages in use, so the history is no longer cut to a few hundred rows; a tuning variable that is no number keeps its default instead of stopping the start; ACME keeps the served certificate when a download fails; the HA status no longer waits for a lock it holds (#1341); SMBIOS settings are saved and written as the PVE GUI writes them; deleting an affinity rule removes it.
  • HTTP to HTTPS: plain HTTP on the HTTPS port gets a redirect to HTTPS again, also with no extra redirect port set, and keeps the port of the address the browser used. http_redirect_port 0 opens port 80 where the service may bind it, and Settings > Server shows which redirects are running.
  • ACME: a renewed certificate is served on the web and console ports without a restart, a background renewal is written to the audit log, and /api/settings/acme/status says whether the certificate on disk is the one being served. A request the CA refuses for its nonce is sent once more, and a dropped download or a refused authorization names the step and the CA's reason.
  • Cross-cluster: a replication run whose migration does not start or fails removes its temporary clone from the source cluster, and a migration whose source node answers late waits up to 60 s and checks whether Proxmox VE started it before it reports an error.
  • Nodes and storage: the node system log shows the newest journal lines and loads quickly; SMBIOS auto-config status reports a node that does not answer after 20 s; SDN route maps and prefix lists of a disconnected cluster say so; downloads by URL from https mirrors work again through the node storage route; the status of an unknown storage balancing group answers 404.
  • ESXi: the migration dialog of an ESXi guest opens again while an ESXi host is registered for migration, and XCP-ng pools are no longer offered as its targets.
  • Interface: the resource list no longer asks the guest agent of a VM without an address on every redraw (one open tab sent about 15 requests a second); more than 250 layout and colour classes the interface uses got their missing style rules, so the Modern notification popover is 320 px wide again and several grids, badges and spacings look as intended; the Corporate Redesigned cluster tabs wrap to a second line; the restart badges of the guest configuration and the tabs of the Modern node dialog follow the selected language.
  • Saving the server settings as form data without the redirect port keeps the stored port, and --requirements names only settings that exist.
  • The VM appliance setup can set a search domain on new setups, so short host names resolve (#1221); the Grafana overview dashboards filter by their dropdowns; the rolling update API reference lists every option (#1184); two plugin syncs at once no longer leave a half-written file (#1134).

⚡ Faster

  • Database commits in WAL mode no longer wait for the disk each time (8.3 ms against 0.12 ms on a test machine), while audit entries, key rotation, failover marks and HA state steps are still synced at once.
  • The page carries English only and every other language is a file of its own, loaded when it is used. index.html went from 8.63 MB to about 8.0 MB; a user of another language loads a language file of about 0.6 to 0.9 MB on top, so their first load is about as large as before. The page is compressed once per encoding (zstd, br, gzip) instead of on every request, and gzip-only clients get it compressed. On Python 3.12 and newer /static/js now goes out compressed as well (about 0.4 MB instead of 1.3 MB).
  • The topology looks guest links up in linear time; before, it took about 4 s of CPU per request at 10,000 guests on SDN vnets.

🌍 Translations

  • Russian as a complete UI language (#1235).
  • The Cloud layout's sidebar, dashboard and instance list, the permission groups of the role dialog, the XCP-ng migration phases, the node disk tables and the OIDC username claim picker in every UI language, and Polish wording corrections.

📦 Images and packaging

  • Debian package: depends on python3-sqlcipher3 and sqlcipher and runs the key step before every start.
  • QNetd helper: the Debian and RPM packages, deploy.sh and the witness installer (--qnetd) ship the root-owned QNetd helper and its installer; the Docker image carries corosync-qnetd and the NSS tools for the sidecar, and docker-compose.yml has a qdevice profile.
  • VM and LXC appliances: an encrypted database on amd64 and arm64, no key in the image, and a release check that fails an image whose database is not encrypted; an arm64 image that fails it is left out of the release.
  • The ESXi OVA images get a build provenance attestation like the qcow2 and tar.xz images.
  • Updates ship the language files in web/i18n along with the page.

⚠️ Behaviour changes

The update dialog lists all of them. The ones most installations notice:

  • Database encryption: on the Debian package, on aarch64 Linux, macOS and Windows pip installs and in the arm64 Docker image the first start encrypts pegaprox.db and syslog.db. A rollback to 1.4.1 has to keep python3-sqlcipher3 or sqlcipher3 installed, or restore the plain copy within the hour it is kept. On the Debian package, run apt-mark manual python3-sqlcipher3 libsqlcipher1 sqlcipher before installing 1.4.1, so the downgrade does not remove them.
  • Portal-only accounts and their API tokens get 403 PORTAL_ONLY outside the Client Portal.
  • Confined accounts get 403 or a reduced answer for host and datacenter reads; scripts that need them run as an unconfined account.
  • Backup servers and confined accounts: the reads of a PBS server itself (status, syslog, network, disks, jobs, datastore settings and usage, updates) answer 403 to an account confined on any cluster the PBS backs up, also to an operator when the PBS backs up another tenant's cluster too. A PBS linked to no cluster counts as backing up every connected cluster: link each PBS to its clusters.
  • Failed Proxmox reads answer 502 or 503 instead of 200 with [] or zeros, and PBS refusals answer 502.
  • Redirects from a Proxmox VE, PBS or ESXi host, a reverse proxy in front of one, a webhook or an ntfy server are no longer followed: point PegaProx at the final address.
  • Credentials typed again: moving the SMTP or LDAP server, a SIEM endpoint, an SDN IPAM or DNS URL, or a plugin's address needs its secret in the same save. The ntfy token and Apprise URLs are write-only.
  • Password expiry: existing local accounts count from the update, so with expiry on they all expire on the same day, one expiry period after the update, unless they change their password before. The warning mails go out before that day.
  • SSH user: nodes are reached as the cluster's SSH user, root when none is set. A cluster whose key was set up for the API user's name on the nodes needs that name in the new SSH user field.
  • Rolling updates: scheduled runs pause and wait like manual ones, a node that cannot be proven back fails or holds the run, and the Ceph gate holds on degraded checks it used to miss.
  • Containers created through the API need a root password or an SSH key, and Start after creation needs vm.start (on XCP-ng xapi.vm.power).
  • Client Portal ISOs: the ISO list, mount and unmount routes refuse every call while allow_iso_mount is off, which is its default. A hoster whose customers mounted ISOs through the API has to switch it on.
  • Migrations with Remove source VM keep the source unless the target was started, and migrated disks get discard on by default.
  • Predictive balancing: a cluster whose stored threshold is 0 or empty, as on clusters saved before the setting existed, now runs at the default of 75 that its page showed. Before, it ran at 0 and rated every node above 0 critical, so predictive balancing triggers less often there now.
  • Figures: storage totals, and the health score of a cluster whose Ceph is not healthy, can come out lower than before.
  • Power cut: after a power cut, not after a crashed process, the last few commits can be missing from the database (docs/history-retention.md).
  • Reverse proxies and IP allowlists that pass only chosen paths must let /i18n/<lang>.json through like /.
  • The notifications plugin stops sending to the old shipped topic on ntfy.sh until a topic of your own is set.
  • SSO: an identity provider whose ID tokens name another audience or issuer than PegaProx is set up for, or that PegaProx cannot verify against the provider's keys, is refused at sign-in now, with the reason on the login page and in the log. Extra audiences go into oidc_audiences.
  • Plain HTTP on the HTTPS port is answered with a redirect to HTTPS.
  • Some panels look slightly different now that every style class has its rule, for example coloured status badges and the Modern notification popover.
  • Classic Corporate shows a notice bar until it is dismissed, and the layout choice no longer offers it: an account that switches away cannot pick it again in the interface.
  • OIDC accounts stay with the identity provider subject they are bound to, also in the Automatic username mode: another person signing in with the same name gets "This sign-in could not be matched to a PegaProx account". After a move to another identity provider, or a change of the subject ids it issues, reset each account's binding in User Management (edit the account, Reset sign-in binding) or with DELETE /api/users/<username>/oidc-binding; the next sign-in binds it again.
  • New LDAP setups start with STARTTLS and the certificate check on: paste your directory's CA certificate into Settings > LDAP before the first sign-in if it is not in the system trust store. Existing setups keep their settings. With the check on, LDAP referrals are no longer followed: use the Global Catalog port (3268, or 3269 with LDAPS) or a base DN inside the domain.
  • Names in requests: a node, storage, guest type or VMID with /, ?, #, %, a backslash or a control character in the query or body of a Proxmox VE cluster request answers 400.
  • Upgrading from 1.4.1: backup, encryption at the first start, the plain copy and the rollback steps are in Upgrading to 1.5.
  • Coming from 1.4.0 or 1.3.x: the behaviour changes of 1.4.1 and 1.4.0 apply as well. See Upgrading to 1.4.

🧭 Known issues

  • Snapshot-Iterative (zero downtime) ESXi migration is still experimental. Use Live Clone or Live Mirror for guests whose data matters.
  • Automatic failover for PegaProx itself is a beta. Try it in your setup before relying on it; manual failover stays one switch away.
  • Change plans are an optional record without an approval gate.
  • Windows guest agent: Prepare VirtIO drivers stages the guest agent package, but in a lab run on Windows Server 2025 its install in the first-boot service failed (error 1722). Install the agent from the VirtIO ISO if it is missing after the migration.
  • arm64 hosts on the Debian repository in the README get a python3-sqlcipher3 with the x86_64 module only and stay on plain SQLite with a warning; field encryption stays on.
  • Container console on some nodes: on a Proxmox VE node where another listener holds port 5900, a container's noVNC console can stay black on the first try, because Proxmox VE hands out the port before the container's console server listens on it. Opening the console again after a few seconds works.
  • Labels in the app: storage balancing is still marked experimental, XCP-ng pools are a Tech Preview and the Cloud layout is a Preview.
  • QDevice: setting a cluster up again after PegaProx removed its QDevice needs Replace, because the QNetd host still holds the cluster's certificate; after pvecm qdevice remove, pvecm status shows "Qdevice (votes 0)" until corosync restarts, which is Proxmox VE's own order. On a host without reachable package sources the QNetd install waits for apt and reports a timeout after 600 s.
  • Tested with fakes: several fixes of this release, among them migration fixes, the rolling update's reboot proof, the XCP-ng host proof, the Ceph gate and Start after creation, were written from documentation and tested with fakes, not run against a real host or cluster. The new ESXi steps were checked against a real ESXi 8.0.3 host and Proxmox VE cluster up to the review (the plan, the network and storage choices, the space check and the refusals, for one guest and as a bulk run), but a copy with these choices, the full disk check and a bulk run that moves guests were tested against recorded ESXi answers only. Try them on a non-critical guest or node first. The QDevice setup did run against real 2-node clusters in our lab, with failover, several clusters on one QNetd host, the Docker sidecar, the local helper, ufw and firewalld.

✅ Quality

The automated suite runs more than 19,800 tests on every change, and more than 4,700 browser tests render every layout in Chromium before a release. The update from 1.4.1 was tested on a seeded encrypted database with 3,000 guests and a week of history, and on a plain one that 1.5.0 encrypted at its first start: every metrics route answered byte for byte as 1.4.1 did, every other difference was an intended change or also differed between two runs of 1.4.1, all stored secrets opened, sign-ins worked and a 2FA account was still asked for its code, a second start changed nothing, and a downgrade to 1.4.1 with SQLCipher installed and the update again worked.

Thank you to everyone who filed, fixed, translated and sponsored along the way. 💚

Thanks in particular to @robbelt, @mdobprv-lab, @NeciMNK, @jostrasser, @CKeckNorthIO, @bgatestmg, @omrzk, @ericcox-kr, @gyptazy, @nvaert1986, @patrickschneider, @cybrwerk, @GreyChame1eon, @DarmokNoob, @willifehler, @K3nshI87, @wisetree911, @Blecherer, @si458, @remipcomaite, @igor-skiba, @Arribacucuru, @buckets-dev and @ralphys, who filed, fixed or translated the issues in this release, and to the researchers who reported security issues to us privately.

💛 Sponsors

PegaProx is AGPL-3.0 and built in the open. Huge thanks to our Platinum sponsors who keep it moving:

💎 Platinum

Sponsor PegaProx: opencollective.com/pegaprox | pegaprox.com/#sponsor

Don't miss a new project-pegaprox release

NewReleases is sending notifications on new releases.