Installing Proxmox VE 9 on a Debian 13 cloud image: what breaks, and the fixes

The official “Install Proxmox VE on Debian 13” steps assume a normal install. A cloud image with cloud-init is not one. These are the nine problems we hit building Proxmox VE VPSes, in the order they bite.

Proxmox publishes no cloud image, so on a VPS the supported route is the one in the official wiki: install Proxmox VE on top of Debian 13. That page assumes a normal Debian install. A cloud image is different — cloud-init owns the hostname and network, the bootloader has no install device recorded, and the network is netplan rather than ifupdown. We converted cloud images in place to build our Proxmox VE VPS product, and every item below broke a build before we fixed it.

  1. The order that works
  2. 1. pmxcfs: “Unable to resolve node name”
  3. 2. apt: “You must correct your GRUB install devices”
  4. 3. Install the kernel first, reboot, then proxmox-ve
  5. 4. Web UI errors: pve-ssl.pem does not exist
  6. 5. “storage does not support content type images”
  7. 6. The bridge config vanishes on reboot
  8. 7. Validating the network file before you reboot
  9. 8. netplan, systemd-networkd and resolved fight ifupdown2
  10. 9. Reboots that look finished but aren’t

The order that works

  1. Fix /etc/hosts and stop cloud-init rewriting it (problem 1).
  2. Preseed GRUB’s install device (problem 2).
  3. Add the Proxmox repository, apt full-upgrade, install proxmox-default-kernel, reboot into the PVE kernel.
  4. Install proxmox-ve postfix open-iscsi chrony, regenerate the node certificate, set storage content types (problems 4–5).
  5. Remove the stock Debian kernel and os-prober.
  6. Write the vmbr0 bridge, validate it, delete the pending interfaces.new, switch off netplan/networkd (problems 6–8).
  7. Reboot, then confirm the node is healthy (problem 9).

Do the package work while the cloud-init network is still in place, and change the network last. Every fix below is from that sequence.

1. pmxcfs: “Unable to resolve node name”

The Proxmox cluster filesystem refuses to start if the node’s hostname resolves to a loopback address:

Unable to resolve node name 'pve-node' to a non-loopback IP address

Cloud images map the hostname to 127.0.1.1, so you fix /etc/hosts — and on the next boot cloud-init puts it back. If the provider’s cloud-init user-data says manage_etc_hosts: true, that beats anything you set in /etc/cloud/cloud.cfg, so manage_etc_hosts: false there does nothing. What user-data can’t override is a module that isn’t in the list. Remove it, then write the hosts file:

as root — use your node's real IPv4 address and hostname
sed -i '/^ - update_etc_hosts$/d' /etc/cloud/cloud.cfg

cat > /etc/hosts <<EOF
127.0.0.1 localhost
203.0.113.10 pve-node.localdomain pve-node pvelocalhost

::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF

hostname -i   # must print 203.0.113.10, not 127.0.1.1
Note

On a VPS behind one-to-one NAT, the node’s own address is the private one on its network interface, not the public IP. Use what ip -4 addr shows.

2. apt: “You must correct your GRUB install devices”

Debian’s cloud images ship grub-pc with no install device recorded. Installing the Proxmox kernel triggers a GRUB reconfiguration, which fails — and takes the whole apt transaction down with it. Preseed the device first. On virtio disks there is no /dev/disk/by-id entry, so the bare device node is what you have:

disk=$(lsblk -ndo PKNAME "$(findmnt -no SOURCE /)")   # usually vda
echo "grub-pc grub-pc/install_devices multiselect /dev/$disk" | debconf-set-selections
echo "grub-pc grub-pc/install_devices_failed_upgrade boolean true" | debconf-set-selections

3. Install the kernel first, reboot, then proxmox-ve

As the wiki describes, Proxmox VE goes on in two steps: the PVE kernel, a reboot into it, then the rest. With the repository added (the wiki has the keyring and the pve-no-subscription source):

apt update && apt full-upgrade -y
apt install -y proxmox-default-kernel
reboot

# after the reboot — confirm, then install the rest
uname -r          # must end in -pve
apt install -y proxmox-ve postfix open-iscsi chrony

# then drop the Debian kernel so GRUB can't boot it
apt remove -y linux-image-amd64 'linux-image-6.12*' os-prober
update-grub

Run dpkg --audit after each install. It should print nothing; anything it lists is a half-configured package you’ll trip over later.

4. Web UI errors: pve-ssl.pem does not exist

If pve-cluster wasn’t running while proxmox-ve installed — which is exactly what problem 1 causes — the node certificate is never generated. pvesh get /nodes shows the node as unknown and complains that /etc/pve/nodes/<node>/pve-ssl.pem doesn’t exist. Start the cluster service and regenerate:

systemctl start pve-cluster
pvecm updatecerts -f
systemctl restart pvedaemon pveproxy pvestatd

5. “storage does not support content type images”

A Debian-based install had no /etc/pve/storage.cfg on our build, so the local storage used built-in defaults — and the first “Create VM” failed because local wouldn’t hold disk images. If you see that error, set the content types explicitly:

pvesm set local --content images,iso,vztmpl,backup,snippets,rootdir
pvesm status --content images     # local should now be listed

6. The bridge config vanishes on reboot

This is the one that cost us the most time. Installing proxmox-ve leaves a pending /etc/network/interfaces.new — Proxmox’s own view of the network, with no bridge. A boot-time service, pvenetcommit, moves any pending file over /etc/network/interfaces early in every boot. So “install proxmox-ve, write vmbr0, reboot” brings the node up with no usable network. Because mv keeps the old file’s timestamp, the file you find afterwards looks older than your edit, as if your write never happened.

The fix is one line, after you’ve written your config:

rm -f /etc/network/interfaces.new

The full story, and how to recover a node that already came up without a network, is in Proxmox lost its network after a reboot?

7. Validating the network file before you reboot

A broken interfaces file on a remote server means a reboot you can’t come back from, so check it first. Three traps:

  • ifquery is not a validator: it exits 0 for a file with a bogus address and an empty bridge-ports.
  • ifup -s does parse properly, but exits non-zero on mere warnings — including bridge-fd 0, which Proxmox itself writes. The exit code can’t be your gate.
  • Before networking.service has ever run, ifupdown2’s lock directory doesn’t exist and every command fails with “Another instance of this program is already running.”

What works: write the new file somewhere else, create the lock directory, and look for lines starting with error:.

/root/interfaces.candidate holds your new config
mkdir -p /run/network
ifup -s -a -i /root/interfaces.candidate 2>&1 | grep '^error:' \
  && echo "do NOT install this file" \
  || install -m 0644 /root/interfaces.candidate /etc/network/interfaces

A minimal single-NIC bridge (replace the NIC name, address and gateway with yours):

/etc/network/interfaces
auto lo
iface lo inet loopback

iface enp1s0 inet manual

auto vmbr0
iface vmbr0 inet static
	address 203.0.113.10/24
	gateway 203.0.113.1
	bridge-ports enp1s0
	bridge-stp off
	bridge-fd 0

source /etc/network/interfaces.d/*

8. netplan, systemd-networkd and resolved fight ifupdown2

Cloud images configure the network with netplan and systemd-networkd. Proxmox uses ifupdown2. Leave both in place and they race at boot. Move netplan’s files aside and hand DNS to a plain resolv.conf:

mkdir -p /etc/netplan.disabled
mv /etc/netplan/*.yaml /etc/netplan.disabled/
systemctl disable --now systemd-networkd.socket systemd-networkd systemd-networkd-wait-online
systemctl disable --now systemd-resolved
rm -f /etc/resolv.conf
printf 'nameserver 1.1.1.1\nnameserver 8.8.8.8\n' > /etc/resolv.conf
systemctl enable networking
Watch out

Whatever netplan configured goes with it — including any IPv6 address. If your server had IPv6, add an iface vmbr0 inet6 static stanza to the new file before you reboot.

9. Reboots that look finished but aren’t

A Proxmox node takes two to three minutes to shut down when it has VMs, because it stops them first. If you script the reboot and poll port 22, you can reach the old boot moments before it goes down and conclude it came back. Compare the boot ID instead:

before=$(cat /proc/sys/kernel/random/boot_id)
reboot
# ...later, over SSH:
[ "$(cat /proc/sys/kernel/random/boot_id)" != "$before" ] && systemctl is-system-running

Then check what matters: the PVE kernel is running, pve-cluster, pvedaemon, pveproxy and pvestatd are active, vmbr0 has the address and the default route, the web UI on port 8006 answers, local accepts images, /dev/kvm exists, and dpkg --audit is clean. Those are the checks we run before any node is handed over.

/dev/kvm deserves a word: without hardware virtualization exposed to your server, Proxmox installs fine, but its VMs won’t start until you turn off KVM acceleration for them — and then they run in slow software emulation. Check before you start.