Running Veeam as a Windows VM on Proxmox VE
1. The Core Architecture: How VBR Operates Inside PVE
- The VBR VM is just the brain: The Windows VM hosting Veeam acts strictly as the management plane, controlling schedules, maintaining the PostgreSQL database, and exposing the console.
– Works the same way as a VMware VM, it just can’t act as it’s own VMware hotadd node when on PVE VM - The PVE Worker handles the heavy lifting: Because PVE lacks a monolithic management layer like vCenter, Veeam requires me to add each individual node in the cluster to the console. Veeam then provisions a lightweight, Linux-based Worker VM onto each host to act as a stateless data mover.
- The Control vs. Data Paths: When a job triggers, my Windows VBR VM talks directly to the Proxmox API to initiate a hypervisor-level snapshot. Once the snapshot is ready, VBR instructs the local Worker VM to mount that snapshot, compress the data blocks, and stream them directly to my backup repository.
┌─── [ Veeam VBR Server (Windows) ] ───┐
│ │
▼ (1. Orders Snapshot via API) ▼ (3. Orders Data Processing)
[ Proxmox VE Host ] [ Veeam PVE Worker VM ]
│ │
▼ (2. Triggers Quiescing) │
[ Target VM + QEMU Agent ] │
│ │
└─────── (4. Reads Snapshot Data) ─────┘
2. Technical Friction Points & Lessons Learned
vmbr0), but that’s it.
- The Hack: Because my management network is VLAN-tagged, the newly deployed Worker VMs immediately drop offline upon creation because they can’t get an IP address. I have to manually jump into the Proxmox GUI, open the hardware settings of the newly provisioned Worker VM, inject the VLAN tag into its virtual NIC, and reboot it.
- The Catch: Every time Veeam pushes an update that redeploys or patches these Worker VMs, this manual configuration gets wiped out. It requires immediate administrative intervention in the PVE GUI to fix the network interfaces after every lifecycle update.
3. The Migration Strategy: Zero-Duplication Streaming to LVM-Thin
Phase 1: Pre-Migration Trim (Dropping the Bloat)
Optimize-Volume -DriveLetter D -Defrag -Verbose
Optimize-Volume -DriveLetter D -ReTrim -Verbose
Phase 2: Live Network Streaming via qm importdisk
- Log in to the Proxmox Web UI.
- Go to Datacenter > Storage > Add and select ESXi.
- Enter a unique ID, your ESXi host Server IP/hostname, and your ESXi administrator Username and Password.
- Check Skip Certificate Verification if your ESXi node uses a self-signed certificate.
- Click Add.
qm importdisk 108 /run/pve/import/esxi/desktopesxi/mnt/ha-datacenter/Desktop-2TB/Veeam/Veeam.vmdk msiNM620
WARNING: Sum of all thin volume sizes (<1.53 TiB) exceeds the size of thin pool nvme-nm620/nvme-nm620 and the size of whole volume group (<953.87 GiB).qm importdisk zero-detection engine kicked in. As the empty space traveled over the LAN, the engine detected the logical zeros and completely dropped them instead of writing them to disk.4. The Finish Line
- Attach the Block Storage: Inside the PVE GUI for VM 108, I went to Hardware, double-clicked the newly created Unused Disk, set it to SCSI, and checked the Discard box (ensuring that future Veeam deletions will actively reclaim space on my LVM-Thin pool).
- Mount the ISO & Fix the NIC: Because the restored Windows VM lacked KVM network drivers, it booted up offline. I used
scpto copy thevirtio-win.isofrom my other cluster node over to this host’s local directory (/var/lib/vz/template/iso/), mounted it to the VM’s virtual CD drive, opened Device Manager, and updated the Ethernet Controller driver. - Rescan & Run: I brought the data disk Online in Windows Disk Management (which instantly recognized the original NTFS/ReFS structure perfectly), opened the Veeam console, and ran a Repository Rescan.
BONUS
iowait percentage. Same problem in my previous blog post when I migrated my email server.sync command via SSH completely hung and stole my terminal shell.- The Block-Level Choke: Veeam streams raw, unallocated data blocks during standard restores. On an un-provisioned LVMthin target, this forces the Proxmox host to perform real-time metadata lookups and extend block structures on every single write loop. This created a massive write-amplification loop that totally choked the SSD controller queue.
- The Unkillable “D-State”: Hard-killing the VM mid-stream locked the
dm-thinkernel driver into an uninterruptible sleep state (Linux D-state). Because the storage layer was frozen waiting on hardware, the kernel completely ignored standard ACPI shutdown signals.
With the storage layer totally unresponsive and
sync frozen, standard reboot commands were completely useless. I had to open a secondary SSH shell and talk directly to the Linux kernel using aggressive, low-level emergency triggers.echo 1 > /proc/sys/kernel/sysrq
b):echo b > /proc/sysrq-trigger











































































