Proxmox VEXXVI · Windows GuestsGetting Windows onto the hypervisor
Installing Windows on Proxmox correctly
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
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
| Decision | Proxmox default | What Windows needs | Cost of changing later |
|---|---|---|---|
ostype | other | win11 for Server 2022/2025 and Windows 11, win10 for Server 2016/2019 and Windows 10 | Cheap, but changes RTC and enlightenments under a running guest |
bios | seabios | ovmf for anything current | High: a BIOS install will not boot under UEFI |
machine | i440fx | q35 | High: pinned at creation for Windows, and device paths move |
scsihw | lsi | virtio-scsi-single | Medium, 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
localtimeoption 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 withostype: othergets 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
otherand 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 syntaxSTORAGE_ID:SIZE_IN_GiBto 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
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:
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:
| Driver | Server 2022 path | Server 2025 path | Device name shown |
|---|---|---|---|
| Storage | vioscsi\2k22\amd64 | vioscsi\2k25\amd64 | Red Hat VirtIO SCSI pass-through controller |
| Network | NetKVM\2k22\amd64 | NetKVM\2k25\amd64 | Redhat VirtIO Ethernet Adapter |
| Memory | Balloon\2k22\amd64 | Balloon\2k25\amd64 | VirtIO 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:
# 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.0Illustrative output
Four things to read here, each of which has been wrong in a real estate:
machinehas resolved to a pinned version,pc-q35-10.0rather thanq35. That is the Windows pinning doing its job. If it still says plainq35, the guest type is not being treated as Windows — checkostype.scsihwsaysvirtio-scsi-singleand the system disk isscsi0, notsata0oride0. A guest whose disk is on SATA has a VirtIO controller with nothing behind it, which looks identical in the GUI summary.bootno longer listside2. The install ISO should be out of the boot order and, ideally, ejected.tpmstate0saysversion=v2.0, not thev1.2default.
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
ostypehas no value named after Windows Server 2022 or 2025. Usewin11; Server 2016/2019 usewin10. Leaving it atothercosts you the local-time RTC and machine-version pinning.- The
scsihwdefault islsi. Every Windows guest wantsvirtio-scsi-single, and the GUI hides how easily a scripted create misses it. ovmfneedsefidisk0withefitype=4m; Windows 11 needstpmstate0withversion=v2.0, because the option defaults tov1.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, andvioscsi\2k22\amd64orvioscsi\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
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?
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?
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.
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.