This post is also available in: Spanish
Upgrading one Proxmox VE server is straightforward when repositories, boot packages, and storage dependencies are already consistent. Upgrading five servers in a small datacenter exposes every inconsistency that accumulated over previous installations and updates.
My lab contains five Proxmox VE hosts. I upgraded them one at a time to reduce the blast radius. Before working on each node, I stopped its virtual machines and LXC containers, updated the existing Proxmox VE 8 installation, changed the Debian and Proxmox repositories, performed the distribution upgrade, and validated the node before moving to the next server.
+---------------------------+ | Administrator | +-------------+-------------+ | Node-by-node migration Proxmox VE 8 → PVE 9.2.6 | v +-------------------------------------------+ | Process for each node | | | | 1. Stop virtual machines and containers | | 2. Fully update Proxmox VE 8 | | 3. Run pve8to9 --full | | 4. Change repositories to Trixie | | 5. Simulate apt full-upgrade | | 6. Upgrade and reboot the node | | 7. Validate services and workloads | +---------------------+---------------------+ | v +--------------------------------+ | CDMX - Primary | | 172.16.10.100 | | PVE 8 → PVE 9.2.6 | +---------------+----------------+ | +----------------------+----------------------+ | | | v v v +-----------------------+ +-----------------------+ +-----------------------+ | Mazatlán | | Mérida | | Guadalajara | | 172.16.10.101 | | 172.16.10.102 | | 172.16.10.103 | | PVE 8 → PVE 9.2.6 | | PVE 8 → PVE 9.2.6 | | PVE 8 → PVE 9.2.6 | +-----------+-----------+ +-----------+-----------+ +-----------+-----------+ | | | +-------------------------+-------------------------+ | v +-----------------------+ | Puebla | | 172.16.10.104 | | PVE 8 → PVE 9.2.6 | +-----------+-----------+ | v +-------------------------------------------+ | Mini datacenter upgraded | | 5 nodes running Proxmox VE 9.2.6 | +-------------------------------------------+That was the plan. In practice, I encountered four important problems:
A
systemd-bootmeta-package that thepve8to9checker required me to remove.A removable GRUB loader that was not configured to receive updates.
Duplicate and mixed Bookworm/Trixie repositories.
Ceph packages from an old Bookworm backport that caused APT to propose removing
proxmox-ve.
On two nodes, the Proxmox management stack was ultimately absent after the package transition. The virtual machines were not necessarily terminated immediately, but commands such as pveversion and services such as pveproxy, pvedaemon, and pvestatd were no longer available. That produced the web-interface message:
Connection error 595: Connection refusedThis article documents the incident and, more importantly, the safeguards I added before upgrading the remaining nodes.
After repairing the affected hosts and applying those safeguards, I completed the upgrade across all five servers. The difficult nodes became canaries that improved the procedure for every node that followed.
This is a lab incident report, not a substitute for the official upgrade guide. Package versions change over time. Always use the current Proxmox VE 8 to 9 upgrade guide and evaluate every APT transaction before accepting it.
My upgrade strategy
I treated the five-server environment as a rolling maintenance operation:
Confirm access through SSH and an out-of-band or local console.
Back up critical guests and configuration.
Stop the VMs and LXC containers on the node being upgraded.
Fully update Proxmox VE 8 before changing repository suites.
Run
pve8to9 --fulland resolve every failure.Change Debian and Proxmox repositories from Bookworm to Trixie.
Run a simulated full upgrade and inspect removals.
Run the real full upgrade only when the Proxmox stack remains installed.
Validate packages, services, storage, networking, boot files, and guests.
Reboot and observe the node before proceeding to the next server.
Stopping the guests was conservative, but it simplified recovery and eliminated guest workload changes while the host package set was transitioning.
Pre-upgrade baseline
Before changing repositories, I now collect a baseline on every host:
hostnamepveversion -vcat /etc/os-releaseuname -rpvesm statusqm listpct listdf -h / /boot /boot/efi 2>/dev/nullpve8to9 --fullI also save the package and repository state:
dpkg-query -W -f='${binary:Package}\t${Version}\n' > /root/packages-before-pve9.txt grep -RnsE \ '^[[:space:]]*deb|^[[:space:]]*(Types|URIs|Suites|Components|Enabled):' \ /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/nullThe pve8to9 script should be run repeatedly. Its recommendations can change after a conflicting package is removed, a new package is installed, or the upgrade reaches another stage.
Issue 1: the systemd-boot meta-package warning
The first failure was:
FAIL: systemd-boot meta-package installed. This will cause problems on upgradesof other boot-related packages. Remove 'systemd-boot'.In Debian Trixie, systemd-boot was split into several packages. The systemd-boot meta-package contains hooks that can automatically manage the bootloader. Proxmox normally manages applicable EFI System Partitions through proxmox-boot-tool, so the meta-package can interfere with that workflow.
However, it must not be removed blindly. First, I identified the actual boot path:
test -d /sys/firmware/efi \ && echo 'Boot mode: UEFI' \ || echo 'Boot mode: BIOS' bootctl statusefibootmgr -vfindmnt /boot /boot/efidpkg -l | grep -E 'proxmox-boot-tool|systemd-boot|grub'On my cdmx node, the important findings were:
Boot mode: UEFIsystemd-boot not installed in ESP.BootCurrent: 0000File: \EFI\proxmox\shimx64.efiThe node was booting through the Proxmox signed shim and GRUB, not through systemd-boot. /etc/kernel/proxmox-boot-uuids did not exist because this GRUB installation was not managed as a proxmox-boot-tool ESP set. I therefore simulated removal first:
apt -s remove systemd-bootAPT proposed removing only systemd-boot, so I proceeded:
apt remove systemd-bootI deliberately kept systemd-boot-efi and did not run apt autoremove. The old kernels remained useful as rollback options.
The exception is a host on which systemd-boot was manually installed and is genuinely used as the bootloader. That configuration must be assessed separately. The official upgrade checker is the authority for whether the meta-package should be removed.
Issue 2: GRUB did not update the removable EFI loader
During initramfs generation, one node reported:
Removable bootloader found at '/boot/efi/EFI/BOOT/BOOTX64.efi',but GRUB packages not set up to update it!The hook supplied the required configuration:
echo 'grub-efi-amd64 grub2/force_efi_extra_removable boolean true' \ | debconf-set-selections -v -uIt then instructed me to reinstall GRUB:
apt install --reinstall grub-efi-amd64My first reinstall attempt failed because the host contained GRUB packages from two releases:
grub-efi-amd64 depends on grub-efi-amd64-bin (= 2.12-9+pmx2)but 2.06-13+pmx7 is to be installedThe correct lesson was not to force one GRUB package. All GRUB components must come from the same repository generation. I paused the bootloader repair, corrected the repositories, completed the package transition, and only then reinstalled GRUB.
After the package set was consistent, I used:
apt install --reinstall grub-efi-amd64update-grubefibootmgr -vI did not reboot while GRUB packages were mismatched. A stale fallback loader under EFI/BOOT/BOOTX64.EFI can load modules from a different GRUB version and leave the machine at a GRUB rescue prompt.
Issue 3: duplicate and mixed repositories
Several nodes had both traditional .list files and newer Deb822 .sources files. APT warned:
Target Packages (pve-no-subscription/binary-amd64/Packages)is configured multiple timesOn one node, the Proxmox VE repository still used Bookworm while another repository already used Trixie. At another point, no Debian base repository was active, so APT could see new Proxmox packages but could not obtain compatible Trixie versions of systemd, LVM, AppArmor, and other base dependencies.
I reviewed all active definitions rather than performing a global search-and-replace:
grep -RnsE \ '^[[:space:]]*deb|^[[:space:]]*(Types|URIs|Suites|Components|Enabled):' \ /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/nullFor PVE 9, the repository set must be internally consistent:
Debian
trixieDebian
trixie-updatesDebian
trixie-securityProxmox VE
trixieThe correct Ceph repository, if Ceph packages are installed
No active
bookworm,bpo12, or duplicate definitions
I kept one definition for each repository and renamed obsolete files with a .disabled suffix so the change remained reversible.
Example Debian Deb822 configuration:
Types: debURIs: http://deb.debian.org/debianSuites: trixie trixie-updatesComponents: main contrib non-free-firmwareSigned-By: /usr/share/keyrings/debian-archive-keyring.gpg Types: debURIs: http://security.debian.org/debian-securitySuites: trixie-securityComponents: main contrib non-free-firmwareSigned-By: /usr/share/keyrings/debian-archive-keyring.gpgExample no-subscription PVE Deb822 configuration:
Types: debURIs: http://download.proxmox.com/debian/pveSuites: trixieComponents: pve-no-subscriptionSigned-By: /usr/share/keyrings/proxmox-archive-keyring.gpgRepository definitions should be taken from the current Proxmox package repository documentation, especially when using an enterprise subscription or Ceph.
Issue 4: APT tried to remove proxmox-ve
The most serious warning appeared during the full upgrade:
W: (pve-apt-hook) You are attempting to remove the meta-package 'proxmox-ve'!The hook correctly stopped the transaction. The wrong response would have been to create /please-remove-proxmox-ve and continue. That file is an explicit authorization to remove the Proxmox meta-package; it is not an upgrade fix.
APT was proposing a large Debian transition, including old libraries being replaced by t64 variants. Those replacements are expected in Trixie. Removing proxmox-ve, pve-manager, pve-qemu-kvm, qemu-server, or libpve-storage-perl is not expected.
I diagnosed the dependency chain with:
apt -s install proxmox-ve apt-cache policy \ proxmox-ve pve-manager pve-qemu-kvm \ ceph-common librados2 librbd1 libcephfs2The real conflict was Ceph:
ceph-common requires librbd1 (= 19.2.3-pve1)but 19.2.5-1~bpo12+2 is selectedThe affected nodes contained Ceph Squid client packages built as Debian 12 backports (~bpo12+2), while the configured Proxmox PVE 9 Ceph repository offered a mutually consistent -pve1 package family. APT preferred the numerically newer backport, but its exact-version dependencies were incompatible with the rest of the Trixie/PVE package set.
The resulting dependency chain was:
incompatible Ceph packages -> libpve-storage-perl cannot be installed -> pve-manager cannot be installed -> proxmox-ve is selected for removalCeph safety boundary
Before changing Ceph packages, I checked whether a node actually provided Ceph services:
ceph -sceph versiondpkg -l | grep -E '^ii[[:space:]]+ceph-(mon|osd|mgr)'My affected hosts contained Ceph client libraries but no Ceph MON, OSD, or MGR packages. That allowed me to align the client packages to the versions offered by the configured Proxmox Ceph Squid repository.
This distinction is critical. If a node is part of an active Ceph cluster, follow Proxmox's coordinated Ceph upgrade procedure. The PVE 8-to-9 documentation requires eligible Ceph deployments to reach Squid before the host upgrade. Do not copy a client-library downgrade command onto a Ceph storage node.
Incident-specific client package alignment
For my client-only nodes, the complete Ceph family had to be selected in one APT transaction because many packages use exact-version dependencies:
apt -s install --allow-downgrades \ ceph-common=19.2.3-pve1 \ ceph-fuse=19.2.3-pve1 \ libcephfs2=19.2.3-pve1 \ librados2=19.2.3-pve1 \ libradosstriper1=19.2.3-pve1 \ librbd1=19.2.3-pve1 \ librgw2=19.2.3-pve1 \ python3-ceph-common=19.2.3-pve1 \ python3-ceph-argparse=19.2.3-pve1 \ python3-cephfs=19.2.3-pve1 \ python3-rados=19.2.3-pve1 \ python3-rbd=19.2.3-pve1 \ python3-rgw=19.2.3-pve1 \ liblttng-ust1t64 \ proxmox-veThe version above records my incident and will become outdated. Before using an equivalent command, inspect the current candidates:
apt-cache policy \ ceph-common ceph-fuse libcephfs2 \ librados2 libradosstriper1 librbd1 librgw2 \ python3-ceph-common python3-ceph-argparse \ python3-cephfs python3-rados python3-rbd python3-rgwI only removed -s after verifying that the simulation installed or preserved the complete Proxmox stack and did not propose additional destructive removals.
Recovery when the Proxmox management stack is missing
On affected nodes, this command failed:
pveversion: command not foundThe service units were also absent:
Unit pvedaemon.service not found.Unit pvestatd.service not found.Unit pveproxy.service not found.That confirmed that this was not merely a stopped proxy. pve-manager and related packages had to be restored.
Before recovery, I avoided rebooting and checked whether guest processes were still running:
ps -eo pid,cmd | grep -E '[k]vm|[l]xc-start'After aligning the Ceph clients and reinstalling proxmox-ve, I completed package configuration and restarted the management plane:
dpkg --configure -aapt-get checksystemctl daemon-reloadsystemctl enable --now pve-clustersystemctl restart pvedaemon pvestatd pveproxyI tested the local API directly:
curl -k -sS -o /dev/null -w 'HTTP %{http_code}\n' \ https://127.0.0.1:8006/api2/json/versionAn HTTP 200 or 401 response proves that the API endpoint is responding. I then verified the package stack with pveversion -v and tested the web interface on port 8006.
A safer procedure for the remaining nodes
The incident changed my workflow. I added explicit gates rather than assuming that a successful apt update meant the repositories were correct.
1. Finish PVE 8 updates first
While repositories still point to Bookworm/PVE 8:
apt updateapt full-upgradepve8to9 --fullResolve all failures before changing suites.
2. Inspect Ceph before changing repositories
ceph version 2>/dev/nulldpkg -l | grep -E '^ii[[:space:]]+ceph-(mon|osd|mgr)' dpkg-query -W -f='${binary:Package}\t${Version}\n' 2>/dev/null \ | grep -E 'ceph|librados|librbd|librgw'An actual Ceph cluster requires its own supported upgrade sequence. Client-only packages still need a repository that supplies a consistent package family.
3. Change repositories and verify every suite
After editing repository definitions:
apt update grep -RnsE \ '^[[:space:]]*deb|^[[:space:]]*(Types|URIs|Suites|Components|Enabled):' \ /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/nullNo active Bookworm or duplicate entries should remain.
4. Require APT to preserve Proxmox
apt -s install proxmox-veapt -s full-upgradeRead the complete REMOVED section. Stop immediately if it contains any of these:
proxmox-vepve-managerpve-qemu-kvmqemu-serverpve-containerpve-ha-managerlibpve-storage-perlDo not treat the Proxmox APT hook as an obstacle to bypass. It is the final guardrail preventing a repository or dependency mistake from dismantling the management stack.
5. Use a full upgrade, not a plain upgrade
A major Debian release transition needs to install replacement dependencies and remove obsolete libraries. A plain apt upgrade kept hundreds of packages back in my environment. Once the simulation was clean, I used:
apt full-upgrade6. Validate before reboot
dpkg --auditapt-get checkpveversion -v systemctl --no-pager --full status \ pve-cluster pvedaemon pvestatd pveproxy pvesm statusqm listpct listupdate-grubefibootmgr -vls -1 /boot/vmlinuz-*-pveI retained at least one known-good PVE 8 kernel until the node completed its first successful PVE 9 boot. I did not run apt autoremove during the upgrade window.
What I learned
APT's removal plan matters more than the upgrade count
Messages such as “569 upgraded, 131 newly installed, 64 to remove” are not automatically wrong during a major Debian transition. The identity of the removed packages is what matters. Old libraries may legitimately be replaced; the Proxmox management stack may not.
Repository consistency includes storage clients
I initially focused on Debian and PVE repositories. The decisive conflict came from Ceph client packages with exact dependencies. Storage-related repositories deserve the same preflight scrutiny as the base operating system.
A meta-package is operationally important
proxmox-ve contains little software itself, but it anchors the supported package set. Its proposed removal signals that APT can no longer satisfy that set. The correct action is to repair the dependency graph, not authorize removal.
Bootloader repair must wait for package consistency
Reinstalling GRUB while grub-common, grub2-common, and grub-efi-amd64-bin came from different releases would have created a boot risk. Repository correction and package alignment came first.
One node at a time limited the damage
Because I upgraded serially, each failure became a new preflight test for the next server. The five-node project reinforced a simple infrastructure principle: canary the procedure, validate every gate, and only then repeat it.
Final checklist
Current backups exist and restore paths are known.
SSH and console access work.
Guests on the target node are stopped or migrated.
PVE 8 is fully updated before repository changes.
pve8to9 --fullreports no unresolved failures.The active bootloader is identified.
Ceph server roles and client package versions are known.
All repositories use the intended suite and none are duplicated.
apt -s install proxmox-vesucceeds.apt -s full-upgradepreserves the Proxmox stack.No
/please-remove-proxmox-vebypass file exists.Package, service, storage, network, and boot checks pass before reboot.
The node is validated after reboot before upgrading the next server.
Conclusion
My Proxmox VE 8-to-9 upgrade was not a single command; it was a dependency, repository, storage-client, and bootloader migration across five different installation histories.
The systemd-boot warning was safe to resolve only after identifying the active GRUB path. The GRUB fallback loader could only be updated safely after all GRUB packages came from the same release. Duplicate and mixed repositories explained the packages kept back. Finally, incompatible Ceph client builds explained why APT wanted to remove proxmox-ve.
The most valuable command in the entire project was not apt full-upgrade. It was the simulation immediately before it:
apt -s full-upgradeWhen a major infrastructure upgrade proposes removing its own management platform, stop. The warning is not the problem—it is evidence of the problem.
Comments