Creating a Windows 11 Virtual Machine on Libvirt

Wednesday, December 27, 2023
Reading time 10 minutes

On this occasion, I feel compelled to document this to ensure it’s not forgotten. The reality is that creating a Windows 11 based virtual machine (VM) may not seem significantly more challenging than what’s been experienced with Windows 10. However, it does present its intricacies, especially as of late 2023. In this article, which I wish could be more concise, I will share the step-by-step instructions that have proven effective for me in successfully running the Windows 11 installation using the Narrator screen reader, facilitated through Spice. I won’t delve into Libvirt extensively this time, as I’ve already provided some relevant information in earlier articles about this tool and its use. Instead, I’ll focus on adding TPM devices, configuring secure boot, and initiating the boot process for Windows 11. My starting configuration involves a system with Debian 12 installed, Libvirt, and a bridged network, as detailed in the respective post.

Obtaining the Windows 11 ISO

It seems that the Windows 11 23h2 ISO image, corresponding to October 2023, doesn’t support activating Narrator with the traditional keyboard combination. Consequently, until Microsoft releases a new version of this image, it’s not suitable for my needs. In my case, I had to download an earlier Windows 11 image (22h2), corresponding to October 2022, to have a baseline where I knew Narrator was functional. You can find a set of such images on sites like Internet Archive (this is the one I downloaded, take into account that it’s in spanish!). It’s worth noting that using Internet Archive may require a torrent client or considerable patience. I opted for Torrent, and the download took about 25 minutes for an approximately 5.8 GB ISO image. Once downloaded, it’s essential to move the ISO image to the directory where Libvirt expects to find it, which in my case is /var/lib/libvirt/iso. I should mention that I’ve renamed the image to win11-22h2.iso, so in the rest of this article, I’ll refer to it as such.

Keeping the VirtIO drivers image for Windows updated is equally important. This image can be obtained from the initial article where I discussed creating VMs with Windows 10.

Installing TPM emulator and secure boot

Windows 11 requires a TPM chip on devices where it will be installed. Several alternatives exist to incorporate this feature into a VM. If the host hardware supports TPM, you could expose the TPM hardware to the virtual machine. However, this approach has the drawback that TPM can’t be utilized in more than one domain simultaneously. In this article, I’ll emulate a TPM module, which works well when no hardware TPM is available or if the same module needs inclusion in multiple VMs.

To acquire the TPM emulator, additional packages are necessary, installable with the following command:

sudo apt-get install ovmf swtpm swtpm-tools

For an odd reason, the TPM emulator module in Debian 12 fails to start due to a permissions issue in a directory. To remedy this, ownership of this directory needs to be granted to the “tss” user:

sudo chown -R tss /var/lib/swtpm-localca

Creating a virtual machine

As is well-known, the virt-install command generates virtual machines. The following arguments should be passed to the command. The only difference is that these include the emulated TPM module, along with some definitions to enable secure boot when starting the operating system:

sudo virt-install --name windows11-vm --cdrom /var/lib/libvirt/iso/win11-22h2.iso --os-variant=win11 --network network=bridged-network,model=virtio --disk size=50,cache=none,bus=virtio --disk path=/var/lib/libvirt/iso/virtio-win.iso,device=cdrom --memory 4096 --sound default --graphics spice,listen= --vcpu 4 --video qxl --noautoconsole --features kvm_hidden=on,smm=on --tpm backend.type=emulator,backend.version=2.0,model=tpm-tis --boot loader=/usr/share/OVMF/OVMF_CODE.secboot.fd,loader_ro=yes,loader_type=pflash,nvram_template=/usr/share/OVMF/

This command should be enough to init the Windows 11 installer on the newly created domain. However, after a few minutes, the domain will suddenly stop, requiring some edits before restarting. Check the domain’s status with the command sudo virsh dominfo windows11-vm. If the “id” attribute isn’t a number or if “status” isn’t “running” in the response, the domain has stopped, and configuration editing is needed.

To edit the domain’s configuration, use the following command:

sudo virsh edit windows11-vm

When editing the XML configuration, disable, for now, booting from the virtual hard drive and give priority to booting from the CDRom containing Windows 11. Then, when Windows 11 initiates the first reboot, priorities will need to be changed again. Follow these steps:

  1. Locate the section called <os> in the XML.
  2. In the <loader> element, set an attribute called secure, with a value of ‘yes’. The element should look like this:
    <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
  3. Locate and delete the <boot> element. By default, this element indicates that the VM should boot from the virtual hard drive.
  4. Locate the element called <devices> and from there, find the virtual hard drive. It will usually look something like this:
<disk type='file' device='disk'>
  <driver name='qemu' type='qcow2' cache='none' discard='unmap'/>
  <source file='/var/lib/libvirt/images/windows11-vm.qcow2'/>
  <target dev='vda' bus='virtio'/>
  <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
  1. Add a new element within the definition of the virtual hard drive. The element will be called <boot>, and it will have an attribute called “order” with a value of “2”. The virtual disk would be defined like this:
<disk type='file' device='disk'>
  <driver name='qemu' type='qcow2' cache='none' discard='unmap'/>
  <source file='/var/lib/libvirt/images/windows11-vm.qcow2'/>
  <target dev='vda' bus='virtio'/>
  <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
  <boot order='2'/>
  1. Find the virtual CDRom containing the Windows 11 ISO image and add another <boot> element, this time with a value of “1”. The complete element should look like this:
<disk type='file' device='cdrom'>
  <driver name='qemu' type='raw'/>
  <source file='/var/lib/libvirt/iso/win11-22h2.iso'/>
  <target dev='sda' bus='sata'/>
  <boot order='1'/>
  <address type='drive' controller='0' bus='0' target='0' unit='0'/>
  1. Save the VM configuration, typically with Ctrl+X, then Y.
  2. Start the domain with sudo virsh start windows11-vm
  3. Check the details to connect via Spice with sudo virsh domdisplay windows11-vm
  4. Connect via Spice, using the IP address of the server where Libvirt is running. Once inside, run Narrator with the Ctrl+Windows+Enter keystroke. The application should start speaking, and it should be possible to begin the installation process.

During installation

When using VirtIO devices, Windows 11 typically does not show any items when selecting the hard drive for installation. To install the VirtIO driver, click on the “Load driver” button, which will open a classic Windows file picker. From there, you need to look in the “This PC” section, in one of the CD drives, one of them will be called “Virtio-win.” Entering it, you can locate and enter the directory called “AMD64”, then locate a folder called W11 and press Enter on it. The next thing that will happen is that a list will be displayed where there is only one device: “RedHat SCSI Device”. Pressing the Next button, after a few seconds, the system will return to the table where you can now see the free space of the virtual disk, ready to be formatted.

Once the installation copies some files and prepares the system, Windows will ask to restart. Once it restarts, go back to the server where Libvirt is running and stop the domain, as it will boot from the installation disk again. Stop the domain like this:

sudo virsh destroy windows11-vm

Then, edit it again:

sudo virsh edit windows11-vm

Here you just need to look for the virtual hard drive element and put <boot order='1'> instead of the “2” that was there before, and the virtual CDRom unit should be <boot order='2'>, although it can be directly removed since it will not be used again.

Once the virtual hard drive is configured to be the first boot item, start the domain again:

sudo virsh start windows11-vm

And you can reconnect via Spice to resume the installation.

Local Account

In my specific use case, Windows 11 serves me better without having to sign in to OneDrive and my Microsoft account. I primarily use it as an operating system for running some continuous integration tasks, and it’s always useful to keep it as clean as possible. That’s why I prefer to sign in with a local account using the following steps:

  1. When Windows 11 restarts and asks for the user’s country (you’ll also hear the system startup sound), press Shift + F10. This should open a Windows command prompt.
  2. Type OOBE\BYPASSNRO and press Enter. If everything has gone well, the system should restart, and you should hear the Windows startup sound again.
  3. From this point, you can proceed. It’s essential not to install the network drivers on next step until Windows is fully installed; otherwise, Windows will connect to the internet and won’t allow configuration without an internet connection.
  4. In the section to select a network connection, a new link called “I don’t have an internet connection” will appear, which can be used to continue with the local account.
  5. Once the system installation is complete, you can install the drivers from “This PC,” just as described in the next section.

Network Drivers

Note: This process installs network drivers during the Windows setup, making it impossible to configure accounts without an internet connection.

When using VirtIO devices, there will also be no network. Normally in this case, you would install Windows and deal with the network later, but this does not work that way in Windows 11. If you cannot connect to the internet, there will come a point where available network connections should be shown, but since no network device is detected, the window simply does not display options. Narrator will only say “flow of available network connections” and will not offer any items in that list. You cannot go back either, and the only button there, which is the “Next” button, is not available, so it is also impossible to reach it.

To solve this problem, it is necessary to install the VirtIO drivers on the system. For this, you need to press the Shift+F10 keystroke. This will open a command prompt in Windows. From here, launch the windows Explorer app by typing the command explorer.exe and pressing Enter, this will allow you to go back to the “This PC” section and search for the virtual CD drive containing the VirtIO drivers (called Virtio-win).

Inside that drive, it’s a matter of running the file called “virtio-win-guest-tools.” It is one of the last files in the list. These Guest tools are some tools that help Windows virtual machines to have better performance and communication with the host. The guest tools, at some point during the installation, will open another executable called “Driver installer setup.” It is recommended to install all the drivers it offers, so there are no major difficulties. Once both the driver installer and guest tools installer are finished, simply go back to the Windows installation window and press the space or enter key, which by default should go to the Next button and allow the rest of the installation.

From this point, the installation should proceed without major difficulties. When finished, you can edit the domain configuration file to remove the Windows 11 ISO images and VirtIO drivers, as they will no longer be necessary.

Removing VM with Windows 11

One last note regarding Windows 11. It seems that the version of Libvirt that comes with Debian 12 does not allow deleting the domain using the sudo virsh undefine command. This happens because a nbram file is used, and Libvirt complains about not being able to delete this type of domain. To delete a domain defined for Windows 11, proceed as follows:

sudo virsh undefine windows11-vm --nvram

Then, manually delete the virtual machine’s virtual disk file, which is normally in the path /var/lib/libvirt/images/windows11-vm.qcow2.


Finally, that’s all. Now you can use Windows 11 in a fully functional virtual machine. As always, there are many optimizations to be made, especially to make Windows take advantage of certain hardware benefits. But that will be for another time.


You can use your Mastodon account to reply to this post.


Linux Administration NAS Tutorials

Windows Windows 11 kvm libvirt