Windows Server 2022 in KVM: virtio drivers, RDP, and licensing
TL;DR
Windows Server 2022 can run reliably in a KVM/QEMU virtual machine on a Linux server if you use UEFI, virtio virtual devices, configure RDP correctly, and activate Windows with a valid license. This guide creates a Windows Server 2022 VM on Ubuntu Server 24.04 LTS with KVM, libvirt, and virtio drivers.
- A small Windows VM requires 4 vCPU, 8 GB RAM, and 80–120 GB of NVMe storage.
- Two ISOs are required to install Windows: a Windows Server 2022 image and a virtio drivers ISO.
- Virtio disk and network adapters provide noticeably better performance than emulated SATA and e1000 devices.
- RDP should only be exposed through a VPN, restricted firewall, or IP allowlist.
- Activation requires a legal Windows Server license: Retail, Volume, SPLA, or your own license with appropriate rights.
- For backups, save the VM XML configuration, virtual disks, BitLocker keys, and guest OS data.
What we are configuring and why
The goal is to deploy Windows Server 2022 in a KVM/QEMU virtual machine on your own VPS or dedicated Linux server. This scenario is used to run Windows applications, Active Directory for small infrastructures, accounting software, an RDS host, test environments, CI agents, game servers, and remote desktops.
KVM is a hypervisor built into the Linux kernel. Combined with QEMU, it allows Windows to run at nearly native performance if the processor supports Intel VT-x or AMD-V hardware virtualization. Libvirt adds convenient virtual machine management through virsh commands, XML configurations, and network profiles.
As a result, you will have a Linux host with one Windows Server 2022 VM that:
- boots in UEFI mode with a QCOW2 or RAW virtual disk;
- uses virtio drivers for disk, network, memory, and the balloon device;
- receives a separate IP address or operates behind NAT;
- is accessible via RDP with Network Level Authentication enabled;
- is protected by firewall rules and login logging;
- can be backed up to an external server or S3-compatible storage.
Why virtio matters
Without virtio, Windows can work with emulated devices: an IDE/SATA disk and an Intel e1000 adapter. This is convenient for the first boot, but creates additional load on the host CPU and limits I/O speed. Virtio is a paravirtualized interface between the guest system and KVM. It reduces overhead and usually delivers significantly higher disk and network performance.
A typical Windows Server 2022 configuration requires the following drivers: viostor or vioscsi for the system disk, NetKVM for networking, Balloon for memory management, viorng for the random number generator, and QEMU Guest Agent for correctly obtaining the IP address, shutting down the VM, and orchestration.
Self-hosted KVM and managed cloud: which to choose
| Criterion | Windows VM in your own KVM | Managed cloud VM |
|---|---|---|
| Hypervisor control | Full: CPU, network, disks, snapshots | Limited to the cloud control panel |
| Cost | More cost-effective for multiple VMs and continuous workloads | Easier to start, but the price may be higher |
| Windows licensing | Must be arranged independently | Often included in the plan or connected separately |
| Backups | Fully under your control | Depend on provider capabilities |
| Infrastructure support | You administer Linux and KVM | The cloud platform maintains the hypervisor |
Self-hosted KVM is justified when you need full control, a custom network design, multiple Windows VMs, access to your own ISOs, isolated labs, or independent backups. If you need one short-term Windows machine without administering a hypervisor, managed cloud is usually simpler.
What is not included in this scenario
This guide is intended for a server with KVM access. A regular VPS running inside someone else's virtual machine may not always be able to run nested virtualization. Before starting, verify that the provider explicitly supports nested virtualization or provides a physical server. If /dev/kvm is unavailable, QEMU will switch to software emulation, and Windows Server will run extremely slowly.
What VPS configuration is required for this task
Resources must be calculated not only for Windows Server 2022, but also for the Linux host, file system cache, QEMU, and a reserve for load peaks. Do not allocate all RAM and vCPUs to the guest: the host needs resources for the kernel, libvirt, disk subsystem, backups, and monitoring.
| Scenario | Windows VM | Host resources | Recommended total |
|---|---|---|---|
| Test environment, 1–2 RDP users | 2 vCPU, 4–6 GB RAM, 64 GB | 2 GB RAM, 1–2 vCPU reserve | 4 vCPU, 8 GB RAM, 100 GB NVMe |
| Production Windows VM, 3–8 RDP users | 4 vCPU, 8–16 GB RAM, 100 GB | 4 GB RAM, CPU reserve | 6–8 vCPU, 16–24 GB RAM, 200 GB NVMe |
| AD, SQL Express, applications | 4–8 vCPU, 16–32 GB RAM | 4–8 GB RAM | 8–12 vCPU, 32–48 GB RAM, NVMe RAID |
| Multiple Windows VMs | Total guest resources | 15–25% RAM and CPU in reserve | Dedicated server |
The minimum practical configuration for one Windows Server 2022 VM is 4 dedicated vCPUs, 8 GB RAM, 100 GB NVMe, and a port of at least 100 Mbps. For comfortable remote work, 16 GB RAM on the host is better: 8–10 GB is allocated to Windows, while the remainder is reserved for Linux and disk cache.
As a basic option, you can choose a VPS with the specified characteristics, but be sure to confirm nested virtualization availability and access to /dev/kvm before ordering. If this is not guaranteed, choose a dedicated server.
When a VPS is not enough
A dedicated server is required when you plan multiple Windows VMs, high SQL Server load, build agents, RDS for many users, demanding CAD/ERP applications, or intensive disk I/O. It is also preferable if you require predictable CPU and IOPS performance, VLANs, multiple public IPs, or no nested virtualization restrictions.
For Windows Server with graphical workloads, KVM without GPU passthrough does not replace a full workstation. Regular RDP is suitable for administration, office tasks, and server applications, but not for 3D visualization, modern rendering, or GPU computing.
How to choose a location
Location affects RDP latency, data storage requirements, and recovery speed from backups. For interactive work, try to keep RTT to the server below 50–70 ms. For a remote office, choose a region close to users. If the Windows VM processes personal data, check the legal requirements for the hosting country and cross-border data transfer in advance.
Checking virtualization support
After your Linux server is provisioned, run the following commands. A non-zero value from the first command and the presence of /dev/kvm mean that KVM can be used.
# Проверяем флаги аппаратной виртуализации процессора.
egrep -c '(vmx|svm)' /proc/cpuinfo
# Проверяем, доступно ли устройство KVM ядра Linux.
ls -l /dev/kvm
# Проверяем, не включена ли виртуализация только в программном режиме.
sudo apt update
sudo apt install -y cpu-checker
kvm-ok
The expected kvm-ok result is: KVM acceleration can be used. If the output says that acceleration is unavailable, do not continue the installation until the platform issue is resolved: TCG emulation is not suitable for permanent Windows Server operation.
Server Preparation
Ubuntu Server 24.04 LTS with current 2026 updates is used as the host below. The approach also applies to Debian 12/13 and other Linux distributions, but package names may differ. Perform all actions as a dedicated user with sudo privileges, not from a persistent root session.
Creating an Administrator and SSH Keys
First, create a user for KVM administration. If the server has already been provisioned with a regular user, this step can be adapted. The public SSH key must be added before disabling password login.
# Создаём отдельного пользователя для администрирования хоста.
sudo adduser admin
# Добавляем пользователя в группу sudo.
sudo usermod -aG sudo admin
# Создаём каталог для SSH-ключей и задаём безопасные права.
sudo install -d -m 700 -o admin -g admin /home/admin/.ssh
# Добавляем ваш публичный ключ; замените строку на содержимое собственного ключа.
echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample your-key' | sudo tee /home/admin/.ssh/authorized_keys > /dev/null
sudo chown admin:admin /home/admin/.ssh/authorized_keys
sudo chmod 600 /home/admin/.ssh/authorized_keys
Open a second SSH session and verify key-based login as the admin user. Change SSH settings only after successful verification. Do not close the current root session until you confirm that the new login works.
# Создаём отдельный файл с безопасными настройками OpenSSH.
sudo tee /etc/ssh/sshd_config.d/99-hardening.conf > /dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
AllowUsers admin
EOF
# Проверяем синтаксис и перезапускаем SSH только при отсутствии ошибок.
sudo sshd -t && sudo systemctl restart ssh
Updates and Basic Tools
Update the system before installing KVM. A reboot is required if the kernel, CPU microcode, or critical virtualization libraries have been updated. Schedule this maintenance window before placing production data in the Windows VM.
# Обновляем пакеты Ubuntu до актуальных исправлений безопасности.
sudo apt update && sudo DEBIAN_FRONTEND=noninteractive apt full-upgrade -y
# Устанавливаем полезные утилиты диагностики и управления.
sudo apt install -y curl wget ca-certificates gnupg lsb-release \
htop jq vim-tiny tmux unzip qemu-utils
# Перезагружаем сервер, если обновлялось ядро или требуется новая версия KVM-модулей.
sudo reboot
Firewall and Brute-Force Protection
There is no need to open RDP port 3389 on the host if the Windows VM uses NAT and RDP is available through a VPN. If the guest has a directly assigned public IP, the firewall must be configured separately on both the Linux host and in Windows Defender Firewall. The example below allows SSH only from your administrative IP. Replace the example address with your own.
# Устанавливаем UFW и Fail2ban для защиты SSH-хоста.
sudo apt install -y ufw fail2ban
# Запрещаем входящие соединения по умолчанию и разрешаем исходящие.
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Разрешаем SSH только с доверенного внешнего адреса.
sudo ufw allow from 203.0.113.25 to any port 22 proto tcp
# Включаем firewall и проверяем итоговые правила.
sudo ufw enable
sudo ufw status verbose
# Запускаем Fail2ban для блокировки перебора SSH-учётных данных.
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
If you have a dynamic IP, do not restrict SSH to a single address until you configure VPN or console access through the provider panel. An alternative may be allowing SSH from a dedicated VPN subnet. Do not open 3389/tcp to the entire internet “for testing”: scanners and bots quickly find such hosts.
Directory Structure
Keep ISOs, virtual machine disks, XML exports, and backups separate. This simplifies permission management, removal of old ISOs, and VM migration. In this example, virtual disks remain in the standard libvirt directory, while source images are stored in /srv/iso.
# Создаём каталоги для ISO, экспортов конфигурации и резервных копий.
sudo install -d -m 0750 /srv/iso
sudo install -d -m 0750 /srv/libvirt-export
sudo install -d -m 0700 /srv/backup
# Проверяем свободное пространство до загрузки ISO и создания дисков.
df -h /srv /var/lib/libvirt/images
Software Installation — Step by Step
On Ubuntu 24.04 LTS, QEMU, libvirt, and OVMF packages are provided by the official Ubuntu repository. In 2026, there is no need to add third-party PPAs for basic Windows Server 2022 operation. Use standard packages: they receive security updates through the regular apt mechanism.
Installing KVM, QEMU, and libvirt
# Устанавливаем KVM/QEMU, libvirt, UEFI-прошивки OVMF и virt-install.
sudo apt install -y qemu-kvm qemu-system-x86 libvirt-daemon-system \
libvirt-clients virtinst ovmf bridge-utils dnsmasq-base
# Запускаем сервис управления виртуальными машинами.
sudo systemctl enable --now libvirtd
# Добавляем администратора в группы управления libvirt и KVM.
sudo usermod -aG libvirt,kvm admin
# Проверяем подключение к локальному гипервизору.
sudo virsh -c qemu:///system list --all
After being added to the groups, log out of the SSH session and log back in. You can verify group membership with the id command. For a server deployment, there is no need to install the virt-manager graphical manager on the host: virsh and virt-install are sufficient.
Downloading Windows Server and virtio ISOs
Download the Windows Server 2022 Datacenter or Standard evaluation ISO only from the official Microsoft Download Center. For permanent operation, use an image that matches your licensing model. Obtain the virtio-win ISO from the official Fedora virtio-win project; in 2026, choose a current stable version compatible with Windows Server 2022.
# Перейдите в каталог хранения образов.
cd /srv/iso
# Скопируйте сюда вручную официальный ISO Windows Server 2022.
# Пример ожидаемого имени файла после загрузки:
sudo ls -lh /srv/iso/Windows_Server_2022.iso
# Скачайте ISO с актуальными драйверами virtio-win из официального зеркала проекта.
sudo wget -O /srv/iso/virtio-win.iso \
https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/virtio-win.iso
# Проверяем размер и тип загруженных ISO.
file /srv/iso/Windows_Server_2022.iso /srv/iso/virtio-win.iso
sudo ls -lh /srv/iso
Before installation, compare the Windows ISO SHA-256 checksum with the value published by the download source. Verifying the virtio-win checksum is also useful, especially if the server is in an environment with elevated security requirements.
# Вычисляем SHA-256 для локальных образов и сверяем с опубликованными значениями.
sha256sum /srv/iso/Windows_Server_2022.iso
sha256sum /srv/iso/virtio-win.iso
Creating a Virtual Disk
QCOW2 supports snapshots and thin provisioning: the file grows as data is written. RAW is usually faster and simpler for external storage systems, but reserves the entire capacity immediately. For a single Windows VM on local NVMe storage, QCOW2 is a convenient starting point. Do not keep unnecessary snapshots for months: they reduce performance and complicate recovery.
# Создаём QCOW2-диск ёмкостью 120 ГБ для Windows Server.
sudo qemu-img create -f qcow2 \
/var/lib/libvirt/images/ws2022.qcow2 120G
# Проверяем параметры виртуального диска.
sudo qemu-img info /var/lib/libvirt/images/ws2022.qcow2
First Launch of the Windows Installer
The command below creates a VM with UEFI, 4 vCPUs, 8 GB RAM, a virtio SCSI controller, and a virtio virtual network adapter. The disk will be invisible to Windows until the vioscsi or viostor driver is loaded from the second ISO. For a server, virtio-scsi is recommended because it is better suited to multiple disks, trim, and I/O queues.
# Создаём и запускаем Windows Server 2022 VM с UEFI и virtio-устройствами.
sudo virt-install \
--name ws2022 \
--memory 8192 \
--vcpus 4 \
--cpu host-passthrough \
--os-variant win2k22 \
--machine q35 \
--boot uefi \
--disk path=/var/lib/libvirt/images/ws2022.qcow2,format=qcow2,bus=scsi,discard=unmap \
--controller type=scsi,model=virtio-scsi \
--disk path=/srv/iso/Windows_Server_2022.iso,device=cdrom \
--disk path=/srv/iso/virtio-win.iso,device=cdrom \
--network network=default,model=virtio \
--graphics vnc,listen=127.0.0.1 \
--video virtio \
--channel spicevmc \
--channel unix,target_type=virtio,target_name=org.qemu.guest_agent.0 \
--rng /dev/urandom,model=virtio \
--noautoconsole
The --graphics vnc,listen=127.0.0.1 parameter does not expose VNC to the internet. To access the installer, create an SSH tunnel from your computer, then connect a VNC client to localhost:5900. Check the port number with virsh vncdisplay.
# Узнаём номер локального VNC-дисплея созданной VM.
sudo virsh vncdisplay ws2022
# На локальном компьютере создаём защищённый SSH-туннель к VNC.
ssh -L 5900:127.0.0.1:5900 admin@SERVER_IP
# На хосте проверяем, что VM действительно запущена.
sudo virsh list --all
If vncdisplay returns :1, use port 5901 instead of 5900. In the VNC client, specify 127.0.0.1:5901. After configuring RDP, VNC can remain as an emergency console, but it must remain accessible only through an SSH tunnel.
Installing the virtio Disk Driver
In the Windows setup interface, select the edition, accept the license terms, and click Load driver on the disk selection screen. Open the second CD-ROM containing the virtio-win ISO. For the configuration in this guide, load the driver from the vioscsi\2k22\amd64 directory. After loading the driver, the 120 GB virtual disk will appear.
- Click Load driver.
- Select the device containing the virtio-win ISO.
- Open
vioscsi, then2k22andamd64. - Confirm installation of the Red Hat VirtIO SCSI driver.
- Select the displayed disk, create partitions automatically, and continue installation.
If you selected the virtio bus instead of scsi, you need the viostor\2k22\amd64 driver. Do not load random drivers for another Windows version: the installer may accept them, but the system will have an unstable configuration.
Installing the Full Driver Set in Windows
After first logging in to Windows, open the second CD-ROM and run virtio-win-guest-tools.exe. This installer adds the network driver, Balloon, QEMU Guest Agent, RNG, and other components. Perform the installation as the local administrator and reboot the VM.
# На Linux-хосте проверяем статус гостевого агента после установки в Windows.
sudo virsh dominfo ws2022
# После установки QEMU Guest Agent в Windows эта команда покажет IP гостя.
sudo virsh domifaddr ws2022 --source agent
# Сохраняем XML-конфигурацию VM до дальнейших изменений.
sudo virsh dumpxml ws2022 | sudo tee /srv/libvirt-export/ws2022.xml > /dev/null
To verify drivers in Windows, open Device Manager. There should be no devices with a yellow icon in the list. Red Hat VirtIO Ethernet Adapter should appear under network adapters, while VirtIO Balloon Driver and VirtIO RNG Device should appear under system devices.
Configuration
After installing Windows, configure the network, RDP, updates, accounts, and licensing. The main principle: do not expose Remote Desktop directly to the internet without restrictions. The safest option is RDP access through WireGuard or a corporate VPN. If a VPN is not yet available, restrict port 3389 to specific external IPs in Windows Firewall and the network firewall.
Network topology: NAT or a dedicated public IP
By default, libvirt uses the default NAT network, usually with the 192.168.122.0/24 subnet. Windows receives a private IP and accesses the internet through the Linux host. This is a good starting option: the guest system is not visible externally, while administration can be performed through a VPN or SSH tunnel.
# Check the libvirt network and the list of DHCP leased addresses.
sudo virsh net-list --all
sudo virsh net-dhcp-leases default
# Check the Windows VM IP through QEMU Guest Agent.
sudo virsh domifaddr ws2022 --source agent
# Check RDP port availability within the private network after enabling it.
nc -vz 192.168.122.100 3389
Replace 192.168.122.100 with the actual Windows IP. For access from a workstation, you can create an SSH tunnel through the Linux host. This does not require opening port 3389 on the public network.
# On the workstation, forward a local RDP port to Windows through the SSH host.
ssh -N -L 13389:192.168.122.100:3389 admin@SERVER_IP
# Then connect with an RDP client to 127.0.0.1:13389.
For permanent access by multiple employees, it is better to use WireGuard. In this case, RDP is permitted only from the VPN subnet, for example 10.66.0.0/24. Publishing a NAT forwarding rule for SERVER_IP:3389 is acceptable only with a strict IP allowlist and additional protection, but a VPN remains the preferred option.
Enabling RDP through PowerShell
Open PowerShell as an administrator in the Windows console or through VNC and run the commands below. They enable Remote Desktop, activate the Windows Firewall rule, require Network Level Authentication, and allow connections only for members of the Remote Desktop Users group.
# Enable Remote Desktop in system settings.
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server'
-Name 'fDenyTSConnections' -Value 0
# Enable the firewall rule for incoming RDP.
Enable-NetFirewallRule -DisplayGroup 'Remote Desktop'
# Require Network Level Authentication for RDP clients.
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'
-Name 'UserAuthentication' -Value 1
# Restart the Remote Desktop Services service.
Restart-Service TermService
Create a separate account for RDP instead of permanently signing in with the built-in Administrator account. Use a long unique password or a domain account if the VM later becomes part of Active Directory. It is better to rename the built-in local administrator and use it only for emergency access through VNC.
# Create a separate local user for RDP administration.
$password = Read-Host -AsSecureString 'Enter a strong password'
New-LocalUser -Name 'rdpadmin' -Password $password -FullName 'RDP Administrator'
# Allow the created user to sign in through Remote Desktop.
Add-LocalGroupMember -Group 'Remote Desktop Users' -Member 'rdpadmin'
# Check who has access to RDP.
Get-LocalGroupMember -Group 'Remote Desktop Users'
Restricting RDP by IP
If RDP is available directly through port forwarding or a dedicated IP, restrict the source on the Windows side. Below is an example rule that allows RDP only from one office and one VPN subnet. After adding it, make sure your current connection will not be blocked.
# Create a stricter RDP rule for trusted sources.
New-NetFirewallRule -DisplayName 'RDP only from trusted networks'
-Direction Inbound -Protocol TCP -LocalPort 3389 -Action Allow
-RemoteAddress '203.0.113.25','10.66.0.0/24'
# Disable the broad built-in rule after verifying the new rule.
Disable-NetFirewallRule -DisplayGroup 'Remote Desktop'
# Check active rules affecting RDP.
Get-NetFirewallRule | Get-NetFirewallPortFilter |
Where-Object { $_.LocalPort -eq '3389' }
The command that disables the built-in group can disable RDP if the new rule is configured incorrectly. Run it only from the VNC console or when you have a second access channel. In an environment with a VPN, it is better to allow only the VPN subnet and not add dynamic home IPs.
Windows Server 2022 licensing and activation
Windows Server 2022 cannot be legally used on a permanent basis without appropriate virtualization rights. KVM does not technically verify the license, but the installation owner is responsible for complying with the terms. Do not use public KMS activators, pirated keys, or third-party scripts: they violate licensing terms and often contain malicious code.
In practice, the following models are encountered:
- Retail/FPP. Usually suitable for one installation, but transfer and virtualization terms must be verified against the specific edition and agreement.
- OEM. Often tied to the original hardware and usually unsuitable for transfer to a rented server.
- Volume Licensing. Corporate MAK or KMS keys with rights defined by the organization's agreement.
- SPLA/CSP-hosted. Licensing through a service provider, often used for rented infrastructure.
- Evaluation. A temporary evaluation edition for testing; it cannot be considered a permanent license.
Windows Server Standard usually grants rights to a limited number of virtual instances when all physical server cores are licensed according to Microsoft rules. Datacenter is designed for dense virtualization. On a rented dedicated server or VPS, licensing is particularly sensitive: BYOL, mobility, and rental rights depend on the agreement and infrastructure type. If in doubt, request written confirmation from a licensing partner or a corporate software attorney.
# Check the installed Windows edition and licensing status.
DISM /online /Get-CurrentEdition
slmgr /dli
slmgr /xpr
# Install your own legitimate product key.
slmgr /ipk XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
# Start activation through an approved Microsoft channel.
slmgr /ato
The slmgr /xpr command will show whether the system is activated permanently, temporarily, or is in an evaluation period. For Volume Licensing, use only the corporate key and the activation method approved by your organization. Do not store the key in VM XML, shell history, a public Git repository, or a backup script.
Configuring updates and the guest agent
In Windows Server 2022, enable automatic updates through Windows Update or a centralized update management system. For a single VM, a monthly maintenance window is optimal: update, reboot, verify RDP and service status. Do not disable updates for “stability”: RDP and Windows services regularly receive critical fixes.
# Check that QEMU Guest Agent is installed and running.
Get-Service -Name QEMU-GA -ErrorAction SilentlyContinue
# Configure automatic agent startup.
Set-Service -Name QEMU-GA -StartupType Automatic
Start-Service -Name QEMU-GA
# Check the RDP service status.
Get-Service -Name TermService
TLS/HTTPS through Caddy or certbot is not needed in this scenario: RDP uses its own TLS encryption, and no web service is deployed on the Linux host. Do not attempt to proxy RDP through a regular HTTP reverse proxy. If browser-based remote access is needed, deploy a separate gateway such as Apache Guacamole behind HTTPS, but this is a separate architecture with additional authentication and security requirements.
Operational verification
Verification should confirm the operation of all layers: the KVM host, VM, network, RDP, and license. Run the commands on the Linux host and in Windows. After every Windows reboot, verify that the machine automatically returns to a working state.
# Check VM autostart after rebooting the Linux host.
sudo virsh autostart ws2022
sudo virsh dominfo ws2022
# Check the guest agent and Windows IP address.
sudo virsh domifaddr ws2022 --source agent
# Check the open RDP port from the Linux host.
nc -vz 192.168.122.100 3389
# Check that the virtual disk contains no format errors.
sudo qemu-img check /var/lib/libvirt/images/ws2022.qcow2
For RDP connections, use a modern client: Microsoft Remote Desktop, mstsc.exe, FreeRDP, or Remmina. Connect through an SSH tunnel or VPN. When connecting for the first time, verify the RDP certificate fingerprint and do not ignore a warning about an unexpected certificate change on a known server.
Backups and maintenance
A snapshot is not a backup. A snapshot is located on the same server and does not protect against VM deletion, SSD failure, host compromise, or administrator error. For Windows Server in KVM, use the 3-2-1 rule: at least three copies of data, on two types of media, with one copy outside the primary server.
What to save
- the
ws2022.qcow2virtual disk or a RAW image; - the VM XML configuration from
virsh dumpxml; - libvirt network settings if custom bridges/VLANs are used;
- Windows System State for Active Directory, certificates, and system roles;
- application databases exported using the DBMS tools themselves;
- BitLocker keys and licensing information stored in a secure secrets manager;
- documentation: IP addresses, VLANs, firewall rules, and the recovery procedure.
For a consistent copy of a running VM, use QEMU Guest Agent and external snapshots, or schedule a short shutdown window. The simplest and most reliable option for a small Windows VM is to shut down the guest normally, copy the image, and then start the VM. This creates several minutes of downtime but makes the copy predictable.
Backup with restic
Restic encrypts backups on the client side and supports S3-compatible storage, SFTP, and standalone servers. Do not store the repository password inside a script or in a user's home directory without restricted permissions. In this example, secrets are kept in a file accessible only to root.
# Install restic from the official Ubuntu repository.
sudo apt install -y restic
# Create a protected environment file for S3-compatible remote storage.
sudo tee /root/.restic-ws2022.env > /dev/null <<'EOF'
export RESTIC_REPOSITORY="s3:https://s3.example.net/windows-kvm-backup"
export RESTIC_PASSWORD="REPLACE_WITH_LONG_UNIQUE_REPOSITORY_PASSWORD"
export AWS_ACCESS_KEY_ID="REPLACE_WITH_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="REPLACE_WITH_SECRET_KEY"
EOF
# Restrict file reading to the root user only.
sudo chmod 600 /root/.restic-ws2022.env
# Initialize an empty encrypted repository.
sudo bash -c 'source /root/.restic-ws2022.env && restic init'
Replace the values in the environment file before running restic init. In production, it is better to pass secrets through secure storage, systemd credentials, or CI/CD secrets. Store the repository password separately from the S3 bucket itself: without it, the encrypted backup cannot be restored.
# Create a script: shuts down the VM, exports XML, saves data, and starts the VM again.
sudo tee /usr/local/sbin/backup-ws2022.sh > /dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
VM="ws2022"
DISK="/var/lib/libvirt/images/ws2022.qcow2"
EXPORT_DIR="/srv/libvirt-export"
ENV_FILE="/root/.restic-ws2022.env"
source "$ENV_FILE"
mkdir -p "$EXPORT_DIR"
virsh dumpxml "$VM" > "$EXPORT_DIR/${VM}.xml"
STATE="$(virsh domstate "$VM")"
if [ "$STATE" = "running" ]; then
virsh shutdown "$VM"
for _ in $(seq 1 60); do
sleep 5
[ "$(virsh domstate "$VM")" = "shut off" ] && break
done
fi
if [ "$(virsh domstate "$VM")" != "shut off" ]; then
echo "VM did not shut down safely" >&2
exit 1
fi
restic backup "$DISK" "$EXPORT_DIR" \
--tag windows-server-2022 \
--exclude '.tmp'
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
virsh start "$VM"
EOF
# Make the script executable and run the first test backup manually.
sudo chmod 700 /usr/local/sbin/backup-ws2022.sh
sudo /usr/local/sbin/backup-ws2022.sh
The script assumes that the VM can be stopped. For SQL Server, Active Directory, and other transactional services, also create logical backups inside Windows. A QCOW2 copy protects the entire VM, but restoring a single object from it may be inconvenient and slow.
# Run backups daily at 03:30 through root cron.
sudo crontab -e
# Add the following line to crontab:
30 3 /usr/local/sbin/backup-ws2022.sh >> /var/log/backup-ws2022.log 2>&1
# Check the list of created snapshots in restic.
sudo bash -c 'source /root/.restic-ws2022.env && restic snapshots'
Recovery verification
A backup is considered functional only after a test recovery. Once per quarter, restore a copy to a separate test disk, import the XML with a new VM name, start it on an isolated network, and verify that Windows boots. Do not turn on the restored copy simultaneously with the original domain controller on the same network: this may cause an AD and DNS conflict.
# Restore the latest snapshot to a separate directory for testing.
sudo install -d -m 0700 /srv/restore-test
sudo bash -c 'source /root/.restic-ws2022.env && restic restore latest --target /srv/restore-test'
# Check the restored QCOW2 image before import.
sudo qemu-img check /srv/restore-test/var/lib/libvirt/images/ws2022.qcow2
Updates and maintenance window
For a single VM, use a maintenance window once a month: update the Linux host, create a backup, update Windows, reboot the VM, and check RDP. Rolling updates are applicable only with multiple application replicas or a cluster; a standalone Windows VM cannot be updated without potential downtime.
Before updating virtio-win, create a snapshot or a full backup. New drivers are usually compatible, but the network or disk driver are critical components. Keep the VNC console available through an SSH tunnel to restore Windows networking if the NetKVM update changes the interface or firewall profile.
Troubleshooting + FAQ
Why does Windows Server 2022 not see the disk in the installer?
Most often, the virtio driver for the correct controller type has not been loaded. If the VM was created with virtio-scsi, the Load driver window requires the path vioscsi\2k22\amd64. For a standard virtio bus, use viostor\2k22\amd64. Also verify that the virtio-win ISO is attached as the second CD-ROM and that the ISO file is not corrupted. Do not change the controller type after installing Windows without first installing the required driver.
Error: KVM acceleration can not be used. What should I do?
Check for /dev/kvm, the vmx or svm flags in /proc/cpuinfo, and the output of kvm-ok. On a VPS, the reason is usually that the provider has not enabled nested virtualization. You cannot independently enable VT-x or AMD-V inside a guest VM. Request nested KVM support or move the Linux host to a dedicated server. Do not run a production Windows Server through QEMU software emulation: performance will be unusable.
What is the minimum suitable VPS configuration?
For one lightweight Windows Server 2022 VM used by one or two administrators over RDP, a practical minimum is 4 vCPU, 8 GB RAM, and 100 GB NVMe. You can allocate 2 vCPU and 4–6 GB RAM to Windows, leaving capacity for the Linux host. The mandatory requirement is more important than the numbers: the VPS must provide access to KVM or officially support nested virtualization. For continuous operation, 16 GB RAM on the host is better.
RDP is enabled, but the connection cannot be established. What should I check?
Check the TermService service in Windows, the Windows Defender Firewall rule, and TCP port availability using Test-NetConnection or nc -vz from the Linux host. If the VM uses NAT, ensure that you connect through an SSH tunnel, VPN, or proper port forwarding. Also check the guest IP through virsh domifaddr ws2022 --source agent. After a NetKVM update, Windows sometimes changes the network profile, causing the firewall to apply stricter rules.
What should I choose for this task: VPS or dedicated?
A VPS is suitable for one small Windows VM, a test environment, or several lightweight RDP users with guaranteed nested virtualization. Dedicated is better for multiple VMs, SQL Server, Active Directory with critical roles, heavy disk I/O, RDS for a team, and requirements for guaranteed resources. Dedicated is also easier to license in some corporate scenarios because the host's physical characteristics are known. The final decision depends on licensing, workload, and isolation requirements.
Windows is slow even though there is enough vCPU and RAM. What is the reason?
Check whether the VM uses a virtio disk and NetKVM rather than emulated SATA/e1000 devices. On the host, run iostat, htop, and check free space: a full QCOW2 disk and slow network storage noticeably degrade responsiveness. Do not create long-lived QCOW2 snapshots. Also ensure that the VM does not receive more vCPU than are physically available under high load: excessive CPU overcommit causes RDP latency.
Can Windows Server 2022 be activated with a key from the internet?
No, you must not use random keys, public KMS servers, activators, or bypass scripts. In addition to violating licensing terms, such tools often contain malicious code and make the server insecure. Use only a key and activation channel for which you have legal rights: corporate MAK/KMS, a subscription, a service provider license, or another verified option. Check the status using slmgr /dli and slmgr /xpr.
Do I need to open port 3389 to the internet for RDP?
No. The preferred option is WireGuard VPN, after which RDP is available only from the VPN subnet. For a single administrator, an SSH tunnel from the Linux host to the private IP of the Windows VM is suitable. Directly opening 3389 increases the risk of password brute-force attacks, vulnerability exploitation, and constant scanning. If direct access is unavoidable, restrict sources by IP, use NLA, strong passwords, MFA through an appropriate gateway, and install updates regularly.
Conclusions and next steps
Windows Server 2022 now runs on the Linux host in KVM with UEFI, a virtio disk, virtio networking, secured RDP, and a controlled licensing model. This configuration is suitable for a small production Windows infrastructure and provides full control over the VM, network, and backups.
- Configure WireGuard and completely close direct RDP access from the internet.
- Test restoration of the restic backup on an isolated test VM before critical data appears.
- As the workload grows, move disks to NVMe RAID, add monitoring for CPU, RAM, IOPS, and RDP latency, then consider a dedicated server or separate VMs for AD, SQL, and application roles.