All posts

Tearing the GPU node down from Proxmox to bare Debian

The GPU node ran Proxmox. I wiped it for bare Debian 13 so the GPU would sit directly under the host kernel, then spent the evening in the NVIDIA driver gauntlet Trixie hands you. The part that caught me was Secure Boot. (It has since gone back to Proxmox.)

The GPU node in my homelab is a single-socket Xeon workstation that for a year ran Proxmox like the rest of the cluster. In June I wiped it and reinstalled bare Debian 13 (Trixie), because the one job I actually want from that box, running CUDA workloads against its GPU, is the one job a hypervisor makes harder. The reinstall took twenty minutes. Getting the driver to load took the rest of the evening, almost all of it on one step: Secure Boot silently refusing a module signed with a key it did not know.

The order of operations that actually works on Trixie is only a few steps, one of which is easy to miss.

Update, September 2026: the node has since rejoined the Proxmox cluster, where it runs the media services, the Kubernetes VM, and local LLM inference. The NVIDIA driver now lives on the Proxmox host itself, so there is still no VFIO passthrough involved. Proxmox VE 9 is built on Debian 13, so the steps below carry over to the host with one change: install the Proxmox kernel headers (proxmox-default-headers) instead of linux-headers-amd64.

Why a hypervisor was the wrong layer here

Proxmox earns its place when you are consolidating many guests onto one machine. GPU compute is the opposite case. To give a virtual machine a real GPU you go through VFIO passthrough, the mechanism that detaches a device from the host and hands it to a guest. That means sorting out IOMMU groups, the device blocks the hardware refuses to separate, keeping the host’s drivers off the card, then handing the whole device to exactly one guest. You end up talking to your GPU through a virtual machine, the card can only ever belong to one VM at a time anyway, and you are carrying all of that machinery for a node that does precisely one thing.

A box that exists only to run one GPU does not need a hypervisor sitting between me and nvidia-smi. Remove the layer and the card is back on bare metal, with the passthrough tax gone along with it.

Before: Proxmox node After: bare Debian 13 CUDA workload (inside the guest) VM: guest OS + NVIDIA driver VFIO passthrough Proxmox host: kernel + KVM GPU one VM owns the card · the driver lives in the guest CUDA workload nvidia.ko (DKMS-built) Debian 13 kernel GPU the card answers to the kernel directly collapse the stack
The same hardware, two stacks. Passthrough buys flexibility a single-purpose GPU node never uses.

Keeping nouveau off the card

Debian ships nouveau, the open-source driver, and loads it at boot. The proprietary module will not bind while nouveau is holding the card. The nvidia-driver package installs its own blacklist for it, so the file below is only a safeguard; the step that matters is rebuilding the initramfs, so the blacklist is already in place in early boot, before nouveau can load from the initramfs and claim the GPU.

# /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0

# then regenerate the initramfs so it sticks at boot
sudo update-initramfs -u

The driver itself: let DKMS do the building

Trixie keeps the NVIDIA driver in the non-free component and its firmware in non-free-firmware, so the sources have to be widened before any of it is installable. Then you install the kernel headers and the driver package, and DKMS compiles the module against your running kernel. That is the reason to use the packaged driver instead of the .run installer: DKMS rebuilds the module on every kernel upgrade, so an apt upgrade does not quietly leave you with a black screen.

# add  contrib non-free non-free-firmware  to your apt sources, then:
sudo apt update
sudo apt install linux-headers-amd64 nvidia-driver

Secure Boot: why nvidia-smi could not see the driver

After the reboot I ran nvidia-smi and got this:

$ nvidia-smi
NVIDIA-SMI has failed because it couldn't communicate with the
NVIDIA driver. Make sure that the latest NVIDIA driver is installed
and running.

The card was fine and the module had built without complaint. The kernel was simply refusing to load it, because Secure Boot was on and DKMS had signed the module with a local key the firmware did not trust yet. There are two ways out. You can turn Secure Boot off in firmware, or enroll that key as a Machine Owner Key and keep the chain of trust intact. I kept Secure Boot and enrolled the key, a one-time step in the MOK manager on the next boot. Nothing in the install itself fails loudly; you only find out at nvidia-smi.

# enroll the DKMS signing key, set a one-time password, then reboot
sudo mokutil --import /var/lib/dkms/mok.pub
# at the blue MOK manager on reboot: Enroll MOK, enter the password, reboot

After that, nvidia-smi came up clean with the card and driver version.

add contrib non-free non-free-firmware to /etc/apt/sources.list blacklist nouveau, update-initramfs -u apt install linux-headers-amd64 nvidia-driver (DKMS builds against your kernel) Secure Boot on? enroll the DKMS key (MOK) the easy step to miss reboot nvidia-smi shows the card + driver version no yes
The whole sequence. Every box except the amber one is mechanical; the amber one is where a clean build still gives you a dead nvidia-smi.

What I got back

nvidia-smi on bare metal, the full card with no virtual machine in the way, and a node that runs my CUDA and Kokkos builds straight against the hardware instead of through a guest. The rest of the cluster is still Proxmox: those nodes are doing the consolidation job Proxmox is good at. This node was not doing that job.

Keeping one bare-metal node beside a Proxmox cluster was awkward on the monitoring side: it had to be watched on its own, outside the tools that cover every other node. The node has since gone back to Proxmox (see the update at the top).