Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français
Lire en français

Install Proxmox VE 9 on an existing Debian 13

By updated

Improve this page

Logo Proxmox

Proxmox VE is not a separate operating system: it is a set of packages laid on top of Debian, so you can install it on a Debian 13 that is already in place. This route is the one to take when you do not control how the machine boots, at a hosting provider that delivers a preinstalled system or in a lab built from a cloud image (a preconfigured disk image, started as is). It is also reproducible, with no graphical console to drive. In return, it asks for four steps that the ISO installer does for you without saying so: making the node name resolvable, adding the repository and checking its key, installing the kernel before the packages, and creating the vmbr0 bridge to move the server address onto it. The cloud image of the test bench of this lesson (the test machine on which the procedure was replayed) adds four traps, none of which names its cause.

What you will learn

Level: Intermediate

By the end of this lesson, you will be able to:

  • Decide whether the Debian route suits your situation, or whether the ISO is better
  • Add the pve-no-subscription repository while checking its signing key instead of copying it
  • Install the Proxmox kernel, reboot onto it, then install the packages
  • Bring up the vmbr0 bridge and move the server address onto it without losing control
  • Recognize the four traps of a cloud image and apply their fix

Prerequisites

This lesson assumes a Debian 13 trixie on which you have root or sudo access, and a rescue access independent of the network you are about to modify, serial console or console of the host hypervisor. It also assumes you know what a network bridge is: understanding Proxmox networking lays it out, and choosing your storage helps you decide where the virtual machine disks will go.

The versions on this page were read on a test bench on 28 October 2026: Debian 13 trixie, Proxmox kernel 7.0.14-26-pve, proxmox-ve 9.2.0, pve-manager 9.2.24, ifupdown2 3.3.0-1+pmx12.

Should you choose this route, or the ISO?

The ISO remains the normal route, and this page does not replace it. The official installer partitions, installs the kernel, creates the bridge and generates the certificate in one pass: everything this lesson makes you do by hand, it does without telling you. Choose the Debian route when the ISO is impossible or unusable, not when it is merely less convenient.

Your situationThe route to take
Physical server whose boot you controlthe official ISO
Hosting provider that delivers a preinstalled Debian, with no boot consolethis page
Virtual machine built from a cloud imagethis page
Need for a partitioning that the installer does not offerthis page
Reproducible installation on a physical serverthe Install Proxmox VE (Automated) entry of the ISO

The Proxmox documentation is explicit on this point: it recommends the installer and only describes the Debian route for special cases. Keep this in mind if you hesitate, and do the installation from the ISO at least once: it is the one you will meet in front of a real server.

What changes with a cloud image?

A cloud image is not a Debian installed by hand, and this is the source of the four traps on this page. It is a disk image prepared to boot without intervention, which the cloud-init service configures at startup. It therefore makes choices that the official procedure does not know about. Here is what a reading of 28 October 2026 shows on the Debian 13 cloud image of the test bench, before any installation (another image may differ):

What the test bench image doesWhat Proxmox expects
the network is entrusted to systemd-networkdthe configuration in /etc/network/interfaces, read by ifupdown
/etc/network/interfaces does not exist at allthis file, which the web interface reads and writes
cloud-init rewrites /etc/hosts at every boota stable entry that resolves the node name
grub-cloud-amd64 serves BIOS and UEFI machines alikean unambiguous boot loader

These differences, to which is added a machine name that resolves to a link-local address, produce four failures, and they share a trait worth stating before reading them: none of them names its cause. The message displayed points each time to something other than the real problem, and two of them hide behind the first ones. The fixes are given along the procedure, at the exact place where the trap springs.

Step 1: make the node name resolvable

The machine name must resolve (be translated into an IP address) to a routable address, otherwise pve-cluster will not start, and the error message will not mention name resolution. This is the prerequisite that the Proxmox documentation puts first, and on the cloud image of the test bench it is not met: the name points to a loopback address.

Terminal window
hostname --ip-address
# 127.0.1.1 <- refused by Proxmox

Also look at what the short name returns, because it is the one Proxmox will use for its certificate:

Terminal window
getent ahosts "$(hostname -s)"
# fe80::5054:d5ff:feb0:10 pve <- a link-local IPv6 address

This fe80:: answer is the fourth trap, and it will strike at step 7. On the test bench, /etc/nsswitch.conf held hosts: files myhostname resolve [!UNAVAIL=return] dns, which queries files then myhostname: with no entry in /etc/hosts for the short name, it is myhostname that answers, and it returns the interface's link-local address.

So write an entry that carries the address, the qualified name and the short name, all three on the same line:

Terminal window
ADRESSE=$(ip -4 -brief addr show enp1s0 | awk '{print $3}' | cut -d/ -f1)
COURT=$(hostname -s)
cat > /etc/hosts <<EOF
127.0.0.1 localhost
$ADRESSE $COURT.lab $COURT
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF

Replace .lab with your real domain, and enp1s0 with the name of your interface. Then check the three results, not only the first:

Terminal window
hostname --ip-address # must return the server address
hostname -f # must return the qualified name, with no extra dot
getent ahosts "$(hostname -s)" # must no longer return an fe80:: address

Step 2: add the repository while checking its key

Comparing a fingerprint copied from a web page verifies nothing: you must check the file you have just downloaded against a published checksum, then let apt verify the signatures. Download the key, then compare its SHA-256 checksum with the one published by the Proxmox documentation.

Terminal window
wget https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg \
-O /usr/share/keyrings/proxmox-archive-keyring.gpg
sha256sum /usr/share/keyrings/proxmox-archive-keyring.gpg
# 136673be77aba35dcce385b28737689ad64fd785a797e57897589aed08db6e45

This checksum was verified on 28 October 2026 and it matched. If yours differs, stop: do not add the repository and start the download again from the official documentation.

Then declare the repository in the deb822 format, the one Debian 13 uses. The Signed-By field ties the repository to this specific key, which is better than a globally accepted key:

Terminal window
cat > /etc/apt/sources.list.d/pve-install-repo.sources <<'EOF'
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF
apt update && apt full-upgrade

The apt update must fetch the repository metadata without any signature error. If it complains about a key, it is the path in Signed-By you must reread, not the key you must import again.

Step 3: install the kernel, then reboot onto it

Order matters, and it is the step most often skipped: the Proxmox kernel is installed alone, you reboot onto it, and only then do you install the packages. Installing them back to back leaves the machine on the Debian kernel, and therefore without the modules that QEMU and LXC need.

Terminal window
apt install proxmox-default-kernel

This is where the first trap springs on a cloud image. On the test bench, the kernel installation pulled in grub-pc as an automatic dependency, the boot loader for BIOS machines, and its configuration fails because no disk is designated for it:

You must correct your GRUB install devices before proceeding:
DEBIAN_FRONTEND=dialog dpkg --configure grub-pc
dpkg: error processing package grub-pc (--configure)

Do not stop at the appearance of failure. The Proxmox kernel is installed and configured: GRUB was regenerated, the menu entries were created, and the machine will indeed reboot onto the Proxmox kernel. What is broken is the state of dpkg: grub-pc stays in a failed configuration, and every following apt will refuse to work until it is dealt with.

Terminal window
dpkg -l | grep '^iF'
# iF grub-pc <- a package installed but not configured

The fix is to install the real EFI boot loader, which replaces grub-pc:

Terminal window
# Only if the machine boots in UEFI: /sys/firmware/efi exists
apt install grub-efi-amd64
dpkg -l | grep '^iF' # must no longer show anything

On a machine that is truly BIOS, do not do this: grub-pc is the right package there, and you must instead designate its disk with dpkg-reconfigure grub-pc. Note that grub-cloud-amd64, the package that creates the ambiguity, remained installed on the test bench: it was not necessary to remove it for the installation to succeed.

When dpkg -l | grep '^iF' no longer returns anything, reboot, then check that the machine is indeed running on the Proxmox kernel:

Terminal window
systemctl reboot
# after reconnecting
uname -r # must end with -pve

The documentation then asks you to remove the Debian kernel, which avoids rebooting onto it by accident:

Terminal window
apt remove linux-image-amd64 'linux-image-6.12*'
update-grub

The update-grub command assumes you boot with GRUB: the documentation declares it unnecessary with systemd-boot, a route this page does not cover.

The documentation also recommends removing os-prober (apt remove os-prober), which scans all partitions of the host. On the test bench image, this package was not installed: if that is your case too, the command will answer that there is nothing to remove, and that is normal.

Step 4: restore name resolution after the reboot

The reboot that step 3 imposes has just undone the prerequisite of step 1. Check it before anything else, because the error it causes will only show up at step 5:

Terminal window
hostname --ip-address
# 127.0.1.1 <- back, even though you had fixed it

If the right address is still there, cloud-init does not manage your /etc/hosts and you can go straight to step 5. Otherwise, this is the second trap: cloud-init rewrote /etc/hosts at boot, from a template that it replays every time. Editing /etc/hosts is therefore useless: it is the template that must be fixed.

Terminal window
cat /etc/cloud/templates/hosts.debian.tmpl
# 127.0.1.1 {{fqdn}} {{hostname}}

Two details of this template explain the failure of step 7, and they cannot be guessed. First, the two variables do not contain the short name: on the test bench, {{fqdn}} was pve.lab.lab and {{hostname}} was pve.lab, so the name pve appeared in no entry. Second, it is /etc/hosts that determines the answer of hostname -f: with this line, the qualified name became pve.lab.lab, the domain doubled.

So write the template with the three forms, spelled out:

Terminal window
ADRESSE=$(ip -4 -brief addr show enp1s0 | awk '{print $3}' | cut -d/ -f1)
COURT=$(hostname -s)
cat > /etc/cloud/templates/hosts.debian.tmpl <<TMPL
## template:jinja
127.0.0.1 localhost
$ADRESSE $COURT.lab $COURT
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
TMPL
# Apply without waiting for a reboot
cloud-init single --name update_etc_hosts --frequency always

Check the three results of step 1 again. The short name must return the server address, and hostname -f a qualified name with no extra dot. Another route exists, setting manage_etc_hosts: false, but it has no effect when the image provider's user-data imposes the opposite value: in cloud-init's documented priority order, user-data wins over /etc/cloud/cloud.cfg.d. The template, for its part, is still read as long as manage_etc_hosts is active.

Step 5: install Proxmox VE

With a resolvable name and a Proxmox kernel at boot, installing the packages goes without surprises.

Terminal window
apt install proxmox-ve postfix open-iscsi chrony

postfix will ask you for a configuration type: choose Local only if the machine does not send mail, or Satellite system if you already have a mail server. chrony keeps the clock, which matters as soon as a cluster comes into play.

Check the three services that carry the interface and the API, then the version obtained:

Terminal window
systemctl is-active pve-cluster pvedaemon pveproxy
# active
# active
# active
pveversion
# pve-manager/9.2.24/66bc407c6d90a67a (running kernel: 7.0.14-26-pve)

If pve-cluster refuses to start with ipcc_send_rec[1] failed: Connection refused, go back to step 1, and to step 4 if cloud-init rewrites your /etc/hosts: the Proxmox documentation points to /etc/hosts for this message, and name resolution is the first cause to rule out.

Step 6: bring up the vmbr0 bridge

Proxmox connects virtual machines to the network through a bridge, and the server address must live on this bridge, not on the physical card. An installation laid on top of Debian keeps its address on the card as long as you do nothing, and no virtual machine will be able to get out.

Write the complete ifupdown configuration, replacing the card name, the address and the gateway with those of your machine. The physical card goes to manual and becomes a port of the bridge:

/etc/network/interfaces
source /etc/network/interfaces.d/*
auto lo
iface lo inet loopback
iface enp1s0 inet manual
auto vmbr0
iface vmbr0 inet static
address 10.10.113.11/24
gateway 10.10.113.1
bridge-ports enp1s0
bridge-stp off
bridge-fd 0

proxmox-ve installs ifupdown2 (a dependency of pve-manager), which can apply a new configuration live, without rebooting. This is exactly what is needed here, because a reboot that goes wrong would leave you without a network.

Terminal window
ifreload -a
ip -brief a show vmbr0

Read the return code of ifreload -a and the output of ip, not the file: if vmbr0 is absent, the configuration is written but was never applied.

This is where the third trap springs, and its message is downright misleading:

error: Another instance of this program is already running.

No instance is running. ifupdown2 places its lock in /run/network/.lock, and on the test bench this directory did not exist (the image entrusts the network to systemd-networkd, but what usually creates this directory was not established). In the ifupdown2 code, the failure to open the lock is reported as a conflict, which sends you looking for a concurrent process that does not exist. The fix takes one command:

Terminal window
mkdir -p /run/network
ifreload -a # returns 0, and the bridge comes up

Then switch the network manager, after you have seen that the bridge does carry its address and never before:

Terminal window
ip -4 -brief a show vmbr0 # must show the server address
systemctl disable --now systemd-networkd.socket systemd-networkd
systemctl enable --now networking

Step 7: open the web interface

The interface answers over HTTPS on port 8006, with a certificate that Proxmox generates itself in the name of the node.

Terminal window
curl -sk -o /dev/null -w '%{http_code}\n' https://127.0.0.1:8006/
# 200

If the port is open but the answer is 000, the first suspect is the fourth trap, the one announced in step 1, which closed on the test bench. The log says so, provided you read it:

Terminal window
journalctl -u pveproxy -n 20
# /etc/pve/local/pve-ssl.pem: failed to use local certificate chain

On the test bench, the cause was a chain with three links, worth understanding once and for all: the node's short name resolved to a link-local IPv6 address, Proxmox placed it in the certificate's SAN (Subject Alternative Name, the list of names and addresses that the certificate declares valid) with its scope identifier, and openssl rejected it.

bad ip address:value=fe80::5054:d5ff:feb0:10%vmbr0
unable to generate pve certificate request

The certificate is therefore never produced, pveproxy starts anyway, listens on its port, and serves nothing. Fix the short name resolution as in steps 1 and 4, then request the regeneration:

Terminal window
pvecm updatecerts --force
systemctl restart pveproxy

Finally, log in at https://ADRESSE:8006, with the PAM realm and the machine's root account. The browser will warn about a self-signed certificate: this is normal at this stage, and serving the interface over verified HTTPS belongs to the next lesson on the web interface.

Troubleshooting

The four failures on this page have in common that they point to something other than their cause, and this table links them to their fix. It lists seven symptoms, some of which are consequences or neighbors of these four failures. Read the middle column before acting: each correction takes one or two commands, provided you aim at the real cause and not at the displayed message.

SymptomReal causeFix
You must correct your GRUB install devicesproxmox-default-kernel pulled in grub-pc, with no disk designatedapt install grub-efi-amd64 in UEFI, dpkg-reconfigure grub-pc in BIOS
An apt refuses to work after the kernel installationa package was left in a failed configurationdpkg -l | grep '^iF' to name it, then deal with that package
ipcc_send_rec[1] failed: Connection refusedmost often, the node name does not resolve to a routable addressfix /etc/hosts, or the cloud-init template if it rewrites it, then cloud-init single --name update_etc_hosts --frequency always
hostname --ip-address is back to 127.0.1.1cloud-init rewrote /etc/hosts at bootfix /etc/cloud/templates/hosts.debian.tmpl, not /etc/hosts
error: Another instance of this program is already runningon the test bench, /run/network/ did not exist and the lock could not be placedmkdir -p /run/network, then ifreload -a
Port 8006 is open and the answer is 000on the test bench, the certificate could not be generated, SAN in fe80::fix the short name resolution, then pvecm updatecerts --force
vmbr0 absent after an ifreload that failedthe configuration is written but never appliedcheck the return code of ifreload -a, do not trust the file

Hands-on practice

The catalog lab does not hand you a ready-made Proxmox: it gives you a bare Debian 13, compliant with the specification, and you install the hypervisor on it by following this lesson. It grades the state of the machine, item by item, and not the commands you typed: an installation carried out differently from the path described here, but reaching the same result, passes just as well.

The six graded items are the presence of Proxmox, its major version, the three services, the answer of the web interface, the vmbr0 bridge carrying the address, and the no-subscription repository. The four traps of this page all stand on that path: that is their reason for being.

Key takeaways

These points sum up the Debian route and the four traps that a cloud image adds to it, each verified on a test bench on 28 October 2026.

  1. The ISO remains the normal route: the Debian route is for when you do not own the boot, or when you want a particular partitioning
  2. The node name must resolve to a routable address, qualified name and short name, otherwise pve-cluster fails on a message that does not mention resolution
  3. The repository key is checked by its SHA-256 checksum, compared with the one in the documentation, and Signed-By ties it to this repository alone
  4. The order is kernel, reboot, then packages: chaining them leaves the machine on the Debian kernel; and grub-pc may arrive with the Proxmox kernel and stay in failed configuration, which blocks the following apt runs without preventing the kernel from being installed
  5. cloud-init rewrites /etc/hosts at every boot: you fix the /etc/cloud/templates/hosts.debian.tmpl template, never the file
  6. The ifreload lock error does not speak of a lock: on the test bench, /run/network/ was missing, and mkdir -p was enough
  7. An open port does not prove a served service: a 000 answer on 8006 may come from a missing certificate, because of a link-local address in the SAN
  8. The address lives on the bridge, and you only cut the network manager after seeing vmbr0 carry that address

Knowledge check

Check that you have grasped the essentials of this guide. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

8 questions
8 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

I take the time to write these guides, test the commands and check the labs so that you can learn for free. If this work helps you, buy me a coffee. It is a simple way to contribute to what comes next for the project.

Buy me a coffee (new tab) Support monthly (new tab) Learn more

Follow the project on LinkedIn