Proxmox VE makes it straightforward to run Windows Server workloads alongside Linux VMs. But spinning up a fresh Windows installation every time you need a test environment is painful. The installer alone takes 20+ minutes, then you’re stuck clicking through OOBE screens, installing drivers, and configuring services. A better approach is to build a reusable Windows Server 2025 template with VirtIO drivers, the QEMU guest agent, and Cloudbase-Init pre-installed. Clone it whenever you need a new VM, and you’re booted into a working desktop in under two minutes.
This guide walks through creating a Windows Server 2025 template on Proxmox VE, starting from the ISO download all the way through sysprep and template conversion. The unattended installation method covered here means zero manual clicks during the Windows setup process.
Prerequisites
- Proxmox VE 8.x host with at least 100GB free storage
- Internet access on the Proxmox host (for downloading ISOs)
- Minimum resources for the template VM: 4 CPU cores, 8GB RAM, 64GB disk
- Root SSH access to the Proxmox node
Step 1: Download the Required ISOs
Two ISOs are needed: the Windows Server 2025 installation media and the VirtIO drivers for paravirtualized hardware. The VirtIO drivers give Windows proper support for the virtual disk controller, network adapter, and display, which results in significantly better performance than emulated hardware.
SSH into your Proxmox node and download both ISOs to the default template directory.
cd /var/lib/vz/template/iso/
wget -O windows-server-2025-eval.iso 'https://go.microsoft.com/fwlink/?linkid=2345730&clcid=0x409&culture=en-us&country=us'
The Windows Server 2025 evaluation ISO is roughly 7.6GB and provides a 180-day trial. If you have a licensed ISO from your Volume Licensing portal, use that instead.
Download the VirtIO drivers ISO from the Fedora project.
wget -O virtio-win.iso 'https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso'
Confirm both files are present and complete.
ls -lh /var/lib/vz/template/iso/ | grep -E "windows|virtio"
You should see both files listed with their full sizes.
-rw-r--r-- 1 root root 754M Sep 12 2025 virtio-win.iso
-rw-r--r-- 1 root root 7.6G Jan 20 16:56 windows-server-2025-eval.iso
Step 2: Create the Autounattend File
Windows supports fully automated installations through an XML answer file called autounattend.xml. When the installer boots, it scans all attached drives for this file and uses it to skip every interactive prompt: language selection, edition choice, disk partitioning, EULA acceptance, and the OOBE wizard.
The answer file also loads VirtIO drivers during the Windows PE phase, which is critical because Windows cannot see the virtual disk without the VirtIO SCSI driver.
Create a directory for the answer file and write the XML.
mkdir -p /tmp/winunattend
Create the autounattend.xml file with a text editor.
vi /tmp/winunattend/autounattend.xml
Add the following content. Replace YOUR_PASSWORD with your desired Administrator password. The password appears in two places (AdministratorPassword and AutoLogon).
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
<settings pass="windowsPE">
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<SetupUILanguage>
<UILanguage>en-US</UILanguage>
</SetupUILanguage>
<InputLocale>en-US</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<DriverPaths>
<PathAndCredentials wcm:action="add" wcm:keyValue="1">
<Path>E:\vioscsi\2k25\amd64</Path>
</PathAndCredentials>
<PathAndCredentials wcm:action="add" wcm:keyValue="2">
<Path>E:\NetKVM\2k25\amd64</Path>
</PathAndCredentials>
<PathAndCredentials wcm:action="add" wcm:keyValue="3">
<Path>E:\viostor\2k25\amd64</Path>
</PathAndCredentials>
<PathAndCredentials wcm:action="add" wcm:keyValue="4">
<Path>E:\qxldod\2k25\amd64</Path>
</PathAndCredentials>
<PathAndCredentials wcm:action="add" wcm:keyValue="5">
<Path>E:\Balloon\2k25\amd64</Path>
</PathAndCredentials>
<PathAndCredentials wcm:action="add" wcm:keyValue="6">
<Path>E:\vioserial\2k25\amd64</Path>
</PathAndCredentials>
</DriverPaths>
</component>
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<DiskConfiguration>
<Disk wcm:action="add">
<DiskID>0</DiskID>
<WillWipeDisk>true</WillWipeDisk>
<CreatePartitions>
<CreatePartition wcm:action="add">
<Order>1</Order>
<Size>100</Size>
<Type>EFI</Type>
</CreatePartition>
<CreatePartition wcm:action="add">
<Order>2</Order>
<Size>16</Size>
<Type>MSR</Type>
</CreatePartition>
<CreatePartition wcm:action="add">
<Order>3</Order>
<Extend>true</Extend>
<Type>Primary</Type>
</CreatePartition>
</CreatePartitions>
<ModifyPartitions>
<ModifyPartition wcm:action="add">
<Order>1</Order>
<PartitionID>1</PartitionID>
<Format>FAT32</Format>
<Label>EFI</Label>
</ModifyPartition>
<ModifyPartition wcm:action="add">
<Order>2</Order>
<PartitionID>2</PartitionID>
</ModifyPartition>
<ModifyPartition wcm:action="add">
<Order>3</Order>
<PartitionID>3</PartitionID>
<Format>NTFS</Format>
<Label>Windows</Label>
</ModifyPartition>
</ModifyPartitions>
</Disk>
</DiskConfiguration>
<ImageInstall>
<OSImage>
<InstallTo>
<DiskID>0</DiskID>
<PartitionID>3</PartitionID>
</InstallTo>
<InstallFrom>
<MetaData wcm:action="add">
<Key>/IMAGE/NAME</Key>
<Value>Windows Server 2025 Standard Evaluation (Desktop Experience)</Value>
</MetaData>
</InstallFrom>
</OSImage>
</ImageInstall>
<UserData>
<ProductKey>
<WillShowUI>OnError</WillShowUI>
<Key>MFY9F-XBN2F-TYFMP-CCV49-RMYVH</Key>
</ProductKey>
<AcceptEula>true</AcceptEula>
</UserData>
</component>
</settings>
<settings pass="specialize">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<ComputerName>WIN2025-TPL</ComputerName>
<TimeZone>UTC</TimeZone>
</component>
<component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<fDenyTSConnections>false</fDenyTSConnections>
</component>
<component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<FirewallGroups>
<FirewallGroup wcm:action="add" wcm:keyValue="RemoteDesktop">
<Active>true</Active>
<Group>Remote Desktop</Group>
<Profile>all</Profile>
</FirewallGroup>
</FirewallGroups>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideLocalAccountScreen>true</HideLocalAccountScreen>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<ProtectYourPC>3</ProtectYourPC>
<SkipMachineOOBE>true</SkipMachineOOBE>
<SkipUserOOBE>true</SkipUserOOBE>
</OOBE>
<UserAccounts>
<AdministratorPassword>
<Value>YOUR_PASSWORD</Value>
<PlainText>true</PlainText>
</AdministratorPassword>
</UserAccounts>
<AutoLogon>
<Enabled>true</Enabled>
<Username>Administrator</Username>
<Password>
<Value>YOUR_PASSWORD</Value>
<PlainText>true</PlainText>
</Password>
<LogonCount>1</LogonCount>
</AutoLogon>
</component>
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<InputLocale>en-US</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
</settings>
</unattend>
A few things to note about this answer file. The IMAGE/NAME value must match the edition name on the ISO exactly. For evaluation ISOs, the name includes “Evaluation,” so using “Windows Server 2025 Standard (Desktop Experience)” without it will cause the installer to stop and wait for manual selection. The VirtIO driver paths reference E:\ because with three IDE CD-ROM drives attached, the VirtIO ISO gets assigned drive letter E.
The product key MFY9F-XBN2F-TYFMP-CCV49-RMYVH is the public KMS client key for Windows Server 2025 Standard Evaluation. It activates the 180-day evaluation period automatically.
Package the answer file into a small ISO that will be mounted as a CD-ROM drive on the VM.
genisoimage -o /var/lib/vz/template/iso/autounattend.iso -J -r /tmp/winunattend/
Step 3: Create the Proxmox VM
Windows Server 2025 requires UEFI boot with Secure Boot and TPM 2.0. The q35 machine type, OVMF BIOS, and pre-enrolled-keys on the EFI disk handle all of this. The ostype win11 setting enables Hyper-V enlightenments that improve Windows performance under KVM.
qm create 900 \
--name win2025-template \
--ostype win11 \
--machine q35 \
--bios ovmf \
--efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=1 \
--tpmstate0 local-lvm:1,version=v2.0 \
--cpu host \
--cores 4 \
--memory 8192 \
--balloon 0 \
--scsihw virtio-scsi-single \
--scsi0 local-lvm:64,iothread=1,discard=on \
--ide0 local:iso/windows-server-2025-eval.iso,media=cdrom \
--ide1 local:iso/autounattend.iso,media=cdrom \
--ide2 local:iso/virtio-win.iso,media=cdrom \
--net0 virtio,bridge=vmbr0 \
--boot order='ide0;scsi0' \
--agent enabled=1 \
--vga qxl
Here is what each setting does.
| Setting | Purpose |
|---|---|
--ostype win11 | Enables Windows-specific optimizations (Hyper-V enlightenments, correct ACPI tables) |
--machine q35 | Modern chipset required for UEFI, TPM, and Secure Boot |
--bios ovmf | UEFI firmware (required for Windows Server 2025) |
--efidisk0 ... pre-enrolled-keys=1 | EFI disk with Microsoft Secure Boot keys pre-loaded |
--tpmstate0 ... version=v2.0 | Virtual TPM 2.0 module (required by Windows Server 2025) |
--balloon 0 | Disable memory ballooning (Windows handles it poorly) |
--scsihw virtio-scsi-single | VirtIO SCSI controller with per-disk IO threads |
--agent enabled=1 | Creates the virtio-serial channel for QEMU guest agent communication |
--vga qxl | QXL display adapter (good for SPICE and VirtIO display driver) |
Step 4: Start the VM and Install Windows
Start the VM. The UEFI firmware will briefly display a “Press any key to boot from CD or DVD” prompt. This prompt only lasts about 5 seconds, so you need to press a key quickly either through the Proxmox console or programmatically.
qm start 900
If you are automating this via CLI, you can send keypresses through the QEMU monitor to catch the boot prompt.
sleep 5
for i in $(seq 1 10); do
pvesh create /nodes/$(hostname)/qemu/900/monitor --command 'sendkey ret' 2>/dev/null
sleep 1
done
Once the installer boots, the autounattend.xml takes over. The entire installation runs hands-free: it loads VirtIO drivers, partitions the disk with a GPT/EFI layout, installs the Desktop Experience edition, sets the Administrator password, enables Remote Desktop, and skips all OOBE screens.
The installation takes 15 to 25 minutes depending on your storage speed. The VM will reboot once or twice during the process. You can monitor progress by taking console screenshots.

pvesh create /nodes/$(hostname)/qemu/900/monitor --command 'screendump /tmp/vm-screen.ppm'
When the installation is complete, you will see the Server Manager dashboard on the desktop, confirming Windows Server 2025 Desktop Experience is fully installed and auto-logged in as Administrator.

Step 5: Install VirtIO Guest Tools and QEMU Agent
The autounattend file loaded the basic VirtIO drivers (storage, network, display) during installation, but two additional components should be installed for full Proxmox integration: the VirtIO guest tools package and the QEMU guest agent.
Connect to the VM via RDP or the Proxmox console and open an elevated Command Prompt or PowerShell window. The VirtIO ISO is still mounted as drive E:.
Install the VirtIO guest tools (includes the balloon driver, serial driver, and display driver).
msiexec /i E:\virtio-win-gt-x64.msi /quiet /norestart

Install the QEMU guest agent, which allows Proxmox to query the VM for IP addresses, run commands, and perform graceful shutdowns.
msiexec /i E:\guest-agent\qemu-ga-x86_64.msi /quiet /norestart
Reboot to ensure all drivers and services load properly.
shutdown /r /t 0
After the reboot, verify the QEMU guest agent is running from the Proxmox host.
qm agent 900 ping
If the agent is working, this command returns silently with no error. You can also query the VM’s network interfaces.
qm agent 900 network-get-interfaces
Step 6: Enable OpenSSH Server (Optional)
Windows Server 2025 includes OpenSSH as an optional feature. Enabling it allows you to manage cloned VMs over SSH without needing RDP or the Proxmox console, which is especially useful for scripted deployments.
Open PowerShell on the VM and install the OpenSSH server feature.
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
The output should show Online: True and RestartNeeded: False.

Start the SSH service and set it to start automatically.
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
Add a firewall rule to allow inbound SSH connections.
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
By default, Windows OpenSSH uses a special authorized_keys file for administrator accounts that prevents password authentication from working. To enable password-based SSH login for the Administrator account, comment out the override in the SSH config.
$config = Get-Content "C:\ProgramData\ssh\sshd_config"
$config = $config -replace "^Match Group administrators", "#Match Group administrators"
$config = $config -replace "^\s*AuthorizedKeysFile __PROGRAMDATA__", "#AuthorizedKeysFile __PROGRAMDATA__"
Set-Content "C:\ProgramData\ssh\sshd_config" $config
Restart-Service sshd
Step 7: Install Cloudbase-Init
Cloudbase-Init is the Windows equivalent of cloud-init. It reads metadata from Proxmox’s cloud-init drive and applies network configuration, hostname, and user settings to cloned VMs automatically. Without it, every clone boots with the same hostname and DHCP network settings.
Download and install Cloudbase-Init silently from PowerShell.
Invoke-WebRequest -Uri "https://github.com/cloudbase/cloudbase-init/releases/download/1.1.6/CloudbaseInitSetup_1_1_6_x64.msi" -OutFile "C:\Users\Administrator\Downloads\CloudbaseInit.msi" -UseBasicParsing
msiexec /i "C:\Users\Administrator\Downloads\CloudbaseInit.msi" /quiet /norestart
Verify the service was installed.
Get-Service cloudbase-init | Format-Table Name, DisplayName, Status, StartType
The service should show as Stopped with Automatic start type. It will run on the next boot after sysprep.
Configure Cloudbase-Init for Proxmox
The default Cloudbase-Init configuration uses the ConfigDrive metadata service, but Proxmox generates cloud-init data in NoCloud format. Update the configuration to use the correct metadata service.
Edit the main configuration file.
notepad "C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf\cloudbase-init.conf"
Set the following content.
[DEFAULT]
username=Administrator
groups=Administrators
inject_user_password=true
first_logon_behaviour=no
config_drive_raw_hhd=true
config_drive_cdrom=true
config_drive_vfat=true
bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe
mtools_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\
verbose=true
debug=true
log_dir=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\log\
log_file=cloudbase-init.log
default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN,requests=WARN
logging_serial_port_settings=
mtu_use_dhcp_config=true
ntp_use_dhcp_config=true
local_scripts_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\
check_latest_version=false
metadata_services=cloudbaseinit.metadata.services.nocloudservice.NoCloudConfigDriveService
plugins=cloudbaseinit.plugins.common.mtu.MTUPlugin,cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin,cloudbaseinit.plugins.windows.createuser.CreateUserPlugin,cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin,cloudbaseinit.plugins.common.localscripts.LocalScriptsPlugin,cloudbaseinit.plugins.common.userdata.UserdataPlugin,cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin,cloudbaseinit.plugins.common.networkconfig.NetworkConfigPlugin
The key change is metadata_services pointing to NoCloudConfigDriveService instead of the default ConfigDriveService. This tells Cloudbase-Init to read the NoCloud format that Proxmox generates when you configure cloud-init settings on a VM.
Also update the unattend configuration file used during the specialize pass.
notepad "C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf\cloudbase-init-unattend.conf"
Set the same metadata_services line in this file as well, pointing to NoCloudConfigDriveService.
Step 8: Sysprep and Shut Down
Sysprep generalizes the Windows installation by removing machine-specific data like the SID, computer name, and hardware-specific drivers. This ensures each clone gets unique identifiers when it boots for the first time.
Cloudbase-Init ships with its own Unattend.xml that hooks into the sysprep process. This ensures Cloudbase-Init runs during the specialize and OOBE passes on cloned VMs.
Run sysprep from an elevated command prompt.
C:\Windows\System32\Sysprep\sysprep.exe /generalize /oobe /shutdown /unattend:"C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf\Unattend.xml"
Sysprep takes a few minutes to complete. The VM will shut down automatically when finished. Wait until the VM status shows “stopped” in Proxmox before proceeding.
qm status 900
Expected output confirming the VM is stopped.
status: stopped
Step 9: Convert to Template
Before converting, remove the installation ISOs and add a cloud-init drive. The cloud-init drive is where Proxmox injects hostname, network, and user configuration when you clone the template.
qm set 900 --delete ide0
qm set 900 --delete ide1
qm set 900 --delete ide2
Add the cloud-init CD-ROM drive.
qm set 900 --ide2 local-lvm:cloudinit
Set the boot order to disk only since the ISOs are removed.
qm set 900 --boot order=scsi0
Convert the VM to a template.
qm template 900
Once converted, the VM icon changes to a template icon in the Proxmox web interface. Template VMs cannot be started directly. They can only be cloned.
Cloning from the Template
Creating a new Windows Server VM from the template takes just a few commands. The full clone copies all disks, so the new VM is completely independent.
qm clone 900 115 --name win2025-dc01 --full true --storage local-lvm
Optionally set cloud-init parameters for the clone. These control the hostname, Administrator password, and network configuration that Cloudbase-Init applies on first boot.
qm set 115 --ciuser Administrator --cipassword 'SecurePass123'
qm set 115 --ipconfig0 'ip=192.168.1.150/24,gw=192.168.1.1' --nameserver 8.8.8.8
Start the clone.
qm start 115
The first boot runs through the sysprep specialize and OOBE passes, which takes 2 to 3 minutes. Cloudbase-Init applies the hostname and network configuration from the cloud-init drive. After that, the VM is ready to use via RDP or the Proxmox console.
Troubleshooting Common Issues
Installer stops at “Select Image” screen
The image name in the autounattend.xml does not match the ISO exactly. Evaluation ISOs include “Evaluation” in the edition name. Check the exact names by booting without the autounattend ISO and noting the options listed. Common correct names are Windows Server 2025 Standard Evaluation (Desktop Experience) and Windows Server 2025 Datacenter Evaluation (Desktop Experience).

“Press any key to boot from CD” timeout
The UEFI boot prompt expires quickly. If you miss it, the VM drops to the UEFI shell or shows “No bootable option found.” Stop the VM, start it again, and send keypresses faster. The sendkey loop in Step 4 handles this by sending Enter every second for 10 seconds.
No network after installation
The VirtIO NetKVM driver was not loaded during installation. Verify the driver path in autounattend.xml matches the Windows version folder on the VirtIO ISO. For Server 2025, the folder is 2k25. For Server 2022, use 2k22.
QEMU guest agent not responding after install
Both MSI packages must be installed: virtio-win-gt-x64.msi (drivers) and guest-agent\qemu-ga-x86_64.msi (agent). The agent also requires the VM to be configured with --agent enabled=1, which creates the virtio-serial communication channel. Reboot the VM after installing both packages.
“Guest has not initialized the display (yet)”
This appears when the EFI disk is corrupted or empty. It typically happens if you manually recreate LVM volumes for the EFI or TPM disks. The fix is to destroy the VM completely with qm destroy and recreate it from scratch. Never manually delete and recreate individual VM disks.
Wrapping Up
With this template in place, spinning up a new Windows Server 2025 VM takes about 2 minutes of clone time plus a 3-minute first boot. The pre-installed VirtIO drivers, QEMU guest agent, and OpenSSH server mean the VM is ready for production use immediately after booting. For environments that need many Windows VMs (Active Directory labs, SQL Server clusters, or multi-tier application testing), this approach saves hours of repetitive setup work.