In the last few months we've made some changes to VMs that finally allow installing and running Windows on them. MS Paint on Cycle is finally a reality.
To make Windows VMs work, we had to add a few things to the platform to support it.
- We needed a way to select a CPU hardware type. Some installers required that the hypervisor report certain CPU features or they would fail. We made this into a config option on your VM.
- We needed a way to install Windows virtio drivers so things like network adapters and storage devices could properly show up.
- We needed a way to make network configuration simpler.
As always with Windows, there are some quirks, gotchas, and pain points. But in the guide below, I'll show you how we solved these issues in our recent platform update, and how to install and run a Windows Server 2025 VM on Cycle with full network connectivity. You can even ping containers within the same environment from your VM!
Part I: Creating the VM
Prereq
In order to deploy VMs on Cycle, you'll need to have a server with the hypervisor feature available. For windows, you'll probably want at least a couple vCPUs and 4GB of RAM. For desktop mode, I'd recommend 4x those numbers.
If you're expecting ingress public internet traffic, you'll need to have an environment with Legacy Mode enabled for IPv4.
Create The VM (Portal)
We'll cover creating the VM in the Portal. It is also possible to use the API to follow this guide.
In cycle, go to your environment, and select the dropdown next to "Deploy Container". Select "Deploy Virtual Machine".
- Enter a name
Note: At this time, SSH keys are only supported with Linux VMs via cloudinit. While the metadata is injected into the virtual machine, SSH keys would need to be synced manually or via a custom script.
- Select 'Image from URL', then enter the URL where the
.isofor your windows install medium can be found. - Set the resource limitations. I highly recommend saving at least 2-3GB of RAM on the host, otherwise your install may freeze up and fail. I wouldn't do less than 4GB on headless mode, and 8-12GB on desktop mode. Windows seems to be RAM greedy.
- For the base volume, if you're installing desktop mode, I recommend at least 40GB. Otherwise the default of 20GB should be ok. If you're using external storage, select that here as well. Add any other block devices you want, then hit 'Next'.
- If you would like ingress internet, set public network to
Enable. Otherwise,Egress Onlywill allow outbound public internet requests. - If this VM needs to go onto a specific node, use the node tags feature to assign it to where you want it. To limit it to any of the selected tags, use 'Match One'. To make sure that all applicable tags are matched on the target server, use 'Match All'.
- Verify everything is good, then hit 'Create Virtual Machine'.
Set Up Additional Configuration Options
Windows VMs require a few extra options to be set before being started.
We need to enable Runtime configuration, and select our OS Flavor as Windows. This tells Cycle to mount the virtio drivers so windows can recognize our virtualized hardware, along with a couple other benefits.
Next, we need to configure the CPU to be a custom one with a modern instruction set if you're running a newer version of Windows, such as Windows Server 2025. I chose a machine type of Q35, and a Haswell CPU, and that seemed to work fine. If you run into issues when running the installer, try adjusting this.
Part II: Installing Windows Into the VM
Connect to VNC
Once you have the VM set up, you can connect over VNC to complete the installation.
You need the environment's VPN container enabled and to be connected to it in order to connect to the VM's VNC viewer.
Once you're connected to the environment's VPN, click the 'Connect to VNC' button in the top right corner of the VM modal.
From here, we'll be able to run the installation onto our base volume.
Booting the Installation Medium
In the versions of Windows Server we tested, you need to 'hit a key' to start the installation. If you're not quick on connecting to VNC, you'll most likely miss it and get dropped into this 'UEFI Interactive Shell'.
Not to worry, we can get it to boot like so:
- List the filesystems (for me it was fs0:)
Shell> map -r
- Enter it and find the EFI bootloader
Shell> fs0: fs0:\> ls
You should see an EFI directory. If not, you can check other file systems using map -r until you find one that does.
- Go into the
Bootdirectory, and run the.efifile. For me on Windows Server 2025, it wasbootx64.efi.
fs0:\> cd EFI\Boot fs0:\> bootx64.efi
You'll be immediately prompted to press a key again (what would appear immediately after booting the VM). Press any key, then select Windows Setup. If you miss hitting the key again, you'll be returned to the prompt where you'll need to repeat the steps above.
The next screen you see should be the GUI installer.
Tip: Set scaling mode to 'Local scaling' in the noVNC viewer to make the mouse a bit easier to control during installation.
Loading the VirtIO Disk Drivers
As long as you've configured the VM on Cycle to be a 'Windows OS' flavor, Cycle will mount the virtio drivers as a CDROM into the VM, so we can utilize those to discover the virtual disk during installation. At this screen, select 'Load Driver'
Navigate to the drive that is titled virtio-win-<something> and expand it.
Scroll down to viostor, expand and select your windows version, and amd64.
Then, click Install. You should now see the base disk as a target for installation, matching the size of the base disk you picked when creating the VM.
Select it, click Next, then continue with the installation.
Go grab a coffee, this will take awhile.
Part III: Configuring Windows To Play Nice With Cycle
Install Network Drivers
Once installed and booted, we need to install the network drivers for the NICs to be recognized
Open powershell, and type the following, replacing any variables for your setup:
pnputil /add-driver "<virtion-win drive>:\NetKVM\<your windows version>\amd64\netkvm.inf" /install
For example, for my installation, it was:
pnputil /add-driver "E:\NetKVM\w11\amd64\netkvm.inf" /install
Windows will install the drivers and apply them to the NICs, allowing them to show up with Get-NetAdapter
Configure Networking
Normally on Cycle VMs running Linux, networking is automatically configured using cloud-init, which is installed in most Linux images. Unfortunately, Windows doesn't have the same luxury. Cycle
Fortunately, the networking information is mounted into the VM anyway, and we've written a handy powershell script to automatically apply them. You can find the code for the script here: https://github.com/cycleplatform/windows-vm-metadata-apply
This script is automatically mounted by Cycle to the virtual machine as a CD-ROM when you select Windows as the OS flavor, so our VM should already have this handy script available as a drive letter and a label cycle-windows-utils.
Once you've located the netconf-apply.ps1 script inside that CD-ROM, execute it in powershell.
If it executed successfully, you should have full networking on both private and public.
Try pinging a private resource (such as env-discovery.cycle) and a public resource if applicable, such as cycle.io
Success!
Final Touches
From here, the sky is the limit. I recommend setting up RDP and connecting that way to finish setting up your instance. It is a bit more robust and supports copying/pasting and transferring files using drag & drop. It'll make the setup that much quicker.
This script currently is only applied when you run it. If the VM is migrated, or Discovery/Gateway services are modified, your VM's networking could break. Resolving is simple: just rerun the script. You could also add it to startup so that this script runs every time the VM boots, much like cloud-init.
Have any other cool tips or tricks when working with Windows VMs? Join our slack at https://slack.cycle.io , or if you're already a member, post into our community at https://cycle.io/community !
