Skip to main content
RunBook Academy

Proxmox VEXXVI · Windows GuestsGetting Windows onto the hypervisor

Installing Windows on Proxmox correctly

Advanced⏱ ~35 minqmvirtio-win ISO

What you'll learn

  • Choose ostype, machine type, firmware and SCSI controller for a Windows guest before the first boot
  • Attach the VirtIO driver ISO and load the storage driver during Windows setup
  • Explain why the Windows installer reports no drives and why that is not a storage fault
  • Name the creation-time settings that are expensive or impossible to change afterwards
  • Verify a finished Windows install against the configuration you intended, not against the fact that it booted

Prerequisites

Verified against Proxmox VE 9.2.4 · Proxmox Backup Server 4.2.5 · Ceph Squid / Tentacle · Debian 13 (Trixie) · Linux kernel 7.0 (PVE 9.2 default) · 2026-08-12

Not yet marked complete on this device.

A Linux guest forgives almost everything you get wrong at creation time. Boot it on an emulated IDE controller and it finds the disk; move it to VirtIO SCSI afterwards and the initramfs already contains the module, so it finds the disk again. Linux re-enumerates its hardware on every boot and has no opinion about which chipset it woke up on.

Windows does not work that way. It binds drivers to device paths during setup, it stores the boot-critical driver set in a registry hive that is only consulted at boot, and it treats a significantly different virtual board as a different computer. Almost every Windows-on-Proxmox ticket traces back to a decision made in the VM creation wizard by someone who was thinking about a Linux guest.

This lesson is about the four decisions that matter and the one step during setup that nothing warns you about.

The four decisions

DecisionProxmox defaultWhat Windows needsCost of changing later
ostypeotherwin11 for Server 2022/2025 and Windows 11, win10 for Server 2016/2019 and Windows 10Cheap, but changes RTC and enlightenments under a running guest
biosseabiosovmf for anything currentHigh: a BIOS install will not boot under UEFI
machinei440fxq35High: pinned at creation for Windows, and device paths move
scsihwlsivirtio-scsi-singleMedium, and it is the classic route to INACCESSIBLE_BOOT_DEVICE

Three of those four defaults are wrong for a modern Windows guest, and none of them is wrong in a way that produces an error message. A VM created with every default installs Windows perfectly, boots, and runs — slowly, on emulated hardware, on a firmware path you will want to leave in two years.

ostype — the value you want is not named after your Windows version

This one catches people because the answer looks like a typo. The qm reference gives the complete enum:

--ostype <l24 | l26 | other | solaris | w2k | w2k3 | w2k8 | win10 | win11 | win7 | win8 | wvista | wxp> — Specify guest operating system.

There is no win2022, no win2k22, no win2025. The web interface labels the same choice “Microsoft Windows 11/2022/2025”, which is the human-readable form of win11. Server 2016 and 2019 sit under win10. If you are scripting VM creation and you reach for a value named after the release on the ISO, qm will reject it, and the temptation is then to leave ostype at its default of other.

Do not. ostype is not cosmetic. Two documented behaviours hang off it:

  • The real-time clock. The localtime option is “enabled by default if the ostype indicates a Microsoft Windows OS”. Windows expects the hardware clock to read local time; Linux expects UTC. A Windows guest with ostype: other gets a UTC hardware clock and a wall clock that is wrong by your UTC offset until something authoritative corrects it. Lesson 6 covers what that does to Kerberos.
  • Machine version pinning. The administration guide states: “For Windows guests, the machine version is pinned during creation, because Windows is sensitive to changes in the virtual hardware.” Pinning is driven by the guest type. Declare other and you have opted the guest out of the protection Part IX described, on the guest type that needs it most.

Firmware: OVMF, and the two disks it drags in

bios defaults to seabios. Choose ovmf for any Windows guest you are building today: Windows 11 and Server 2025 expect UEFI, Secure Boot is a baseline control in most estates, and a SeaBIOS install cannot be converted to UEFI by flipping the setting — the disk has an MBR and no EFI system partition.

OVMF needs somewhere to keep its variables, which is efidisk0:

--efidisk0 — Configure a disk for storing EFI vars. Use the special syntax STORAGE_ID:SIZE_IN_GiB to allocate a new volume.

Two sub-options matter. efitype accepts 2m or 4m and defaults to 2m; pre-enrolled-keys is a boolean defaulting to 0. You want efitype=4m — the 2 MB variable store is the legacy size and has no room for the full Microsoft key set — and pre-enrolled-keys=1 if you intend to use Secure Boot, which enrols the standard Microsoft certificates so the Windows bootloader is trusted on first boot.

Windows 11 additionally requires a TPM. That is tpmstate0, whose version sub-option accepts v1.2 or v2.0 and defaults to v1.2 — which Windows 11 will refuse. Set version=v2.0 explicitly.

Machine type: q35

i440fx is a 1996 desktop chipset with a PCI bus. q35 gives you a PCIe bus, which is what modern device models, PCIe passthrough and anything with more than a handful of devices actually want. Proxmox picks q35 for the Windows guest types in the wizard; if you are scripting, set it.

The reason to get it right at creation is the pinning quoted above. Windows guests have their machine version pinned when the VM is created, so the type you choose is the type you keep until you deliberately change it — and changing the chipset family under an installed Windows moves every device to a new PCI path, which is the same class of event as changing the disk controller.

The SCSI controller, and the default that surprises everyone

Read this from the qm reference and note the default:

--scsihw <lsi | lsi53c810 | megasas | pvscsi | virtio-scsi-pci | virtio-scsi-single> — SCSI controller model (default: lsi)

The API default is an emulated LSI 53C895A. The GUI wizard offers something better, but any qm create that does not name scsihw gets lsi, and so does any Terraform or Ansible module that leaves the field unset.

virtio-scsi-single is the choice for Windows. Both Proxmox best-practice wiki pages name it, and “single” means one controller per disk, which is what makes iothread=1 useful — each disk gets its own I/O thread instead of contending on a shared one.

And this is where the interesting failure lives, because choosing virtio-scsi-single is exactly what makes the Windows installer unable to find your disk.

Creating the VM

Configuration changecreate a Windows Server 2022/2025 VM
VMID=9100
STORE=local-zfs
ISOSTORE=local
WINISO=SERVER_EVAL_x64FRE_en-us.iso

qm create "$VMID" \
--name win2022-base \
--ostype win11 \
--machine q35 \
--bios ovmf \
--efidisk0 "$STORE:1,efitype=4m,pre-enrolled-keys=1" \
--tpmstate0 "$STORE:1,version=v2.0" \
--cpu host \
--sockets 1 --cores 4 \
--memory 8192 --balloon 0 \
--scsihw virtio-scsi-single \
--scsi0 "$STORE:64,cache=writeback,discard=on,iothread=1,ssd=1" \
--net0 "virtio,bridge=vmbr0" \
--agent enabled=1 \
--ide2 "$ISOSTORE:iso/$WINISO,media=cdrom" \
--ide0 "$ISOSTORE:iso/virtio-win.iso,media=cdrom" \
--boot "order=ide2;scsi0"

Three lines deserve a sentence each.

--balloon 0 disables ballooning for now. The administration guide is blunt about Windows: “For Windows OSes, the balloon driver needs to be added manually and can incur a slowdown of the guest, so we don’t recommend using it on critical systems.” Install first, decide about ballooning later — Lesson 2 covers what “added manually” involves and Lesson 4 covers when it is worth it.

--ide0 is the second CD drive, holding the VirtIO driver ISO. Both Proxmox best-practice pages specify a second CD/DVD drive on the IDE bus, number 0, and they specify IDE for a reason that is almost funny: the driver you need in order to see a VirtIO device cannot itself live on a VirtIO device. IDE is emulated, WinPE has an inbox driver for it, and so the ISO is readable from the first second of setup.

--boot "order=ide2;scsi0" puts the Windows ISO ahead of the empty disk so the installer starts. Remove ide2 from the order after installation, or a forgotten ISO will send a rebooting production guest back into setup.

Fetch the driver ISO onto the node first — the stable image is published by the virtio-win project:

Read-only / Safedownload the VirtIO driver ISO to the ISO store
ISO_DIR=/var/lib/vz/template/iso

curl -fSL -o "$ISO_DIR/virtio-win.iso" \
https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso

ls -lh "$ISO_DIR/virtio-win.iso"

The step nothing warns you about

Boot the VM and run setup normally until the disk selection screen. It will be empty.

Click Load driver, browse to the second CD drive, and select the directory matching your Windows version and architecture. Both Proxmox best-practice pages give the paths verbatim:

DriverServer 2022 pathServer 2025 pathDevice name shown
Storagevioscsi\2k22\amd64vioscsi\2k25\amd64Red Hat VirtIO SCSI pass-through controller
NetworkNetKVM\2k22\amd64NetKVM\2k25\amd64Redhat VirtIO Ethernet Adapter
MemoryBalloon\2k22\amd64Balloon\2k25\amd64VirtIO Balloon Driver

Storage is the only one setup strictly requires — load it and the disk appears immediately. Loading network and balloon at the same time is worth the extra ninety seconds, because it means the guest has a working NIC the moment it reaches the desktop instead of after a trip to Device Manager.

Then install as normal. The remaining drivers and the services go on after first boot, which is Lesson 2.

Verifying, in a way that can fail

“It booted” verifies that a disk was found. It does not verify that the disk was found on the controller you intended, or that the firmware is the one you chose. Check the configuration against the intent:

Read-only / Safeconfirm the guest matches the intended configuration
# qm config 9100 | grep -E '^(ostype|machine|bios|scsihw|scsi0|efidisk0|tpmstate0|net0|agent|boot):'
agent: enabled=1
bios: ovmf
boot: order=scsi0
efidisk0: local-zfs:vm-9100-disk-0,efitype=4m,pre-enrolled-keys=1,size=1M
machine: pc-q35-10.0
net0: virtio=BC:24:11:3A:00:1F,bridge=vmbr0
ostype: win11
scsi0: local-zfs:vm-9100-disk-1,cache=writeback,discard=on,iothread=1,size=64G,ssd=1
scsihw: virtio-scsi-single
tpmstate0: local-zfs:vm-9100-disk-2,size=4M,version=v2.0

Illustrative output

Four things to read here, each of which has been wrong in a real estate:

  1. machine has resolved to a pinned version, pc-q35-10.0 rather than q35. That is the Windows pinning doing its job. If it still says plain q35, the guest type is not being treated as Windows — check ostype.
  2. scsihw says virtio-scsi-single and the system disk is scsi0, not sata0 or ide0. A guest whose disk is on SATA has a VirtIO controller with nothing behind it, which looks identical in the GUI summary.
  3. boot no longer lists ide2. The install ISO should be out of the boot order and, ideally, ejected.
  4. tpmstate0 says version=v2.0, not the v1.2 default.

Inside the guest, the equivalent check is that Device Manager shows no devices with a warning triangle, and that the system disk sits under the Red Hat VirtIO SCSI controller rather than a Microsoft Storage Controller. Lesson 2 turns that into something you can assert from the host.

Key takeaways

  • ostype has no value named after Windows Server 2022 or 2025. Use win11; Server 2016/2019 use win10. Leaving it at other costs you the local-time RTC and machine-version pinning.
  • The scsihw default is lsi. Every Windows guest wants virtio-scsi-single, and the GUI hides how easily a scripted create misses it.
  • ovmf needs efidisk0 with efitype=4m; Windows 11 needs tpmstate0 with version=v2.0, because the option defaults to v1.2. Both volumes are guest data and belong in your backups and your DR procedure.
  • The Windows installer cannot see a VirtIO disk. That is the driver ISO on a second CD drive on IDE, Load driver, and vioscsi\2k22\amd64 or vioscsi\2k25\amd64 — not a storage fault.
  • Pin the virtio-win version. The Proxmox wiki maintains a known-issues list precisely because some releases have shipped I/O defects.
  • Firmware, machine family and controller are cheap to choose and expensive to change. Decide them before the first boot.

Knowledge check

Knowledge check · 4 questions

  1. Q1. You are scripting the creation of Windows Server 2025 VMs with qm create. Which ostype value should the script use, and why does it matter beyond labelling?

  2. Q2. A colleague reports that the Windows installer shows an empty disk list on a VM you created, and proposes deleting and recreating the virtual disk. What is actually happening?

  3. Q3. Which of these are genuine consequences of leaving Proxmox defaults in place when creating a Windows Server guest with qm create? Select all that apply.

  4. Q4. The VirtIO driver ISO should be attached to a second CD drive on the IDE bus rather than on a SCSI or VirtIO bus.

Passing score: 75%. Answers are checked in this browser.