Skip to content

Building a Windows Server AMI on Linux

The Primcoat Team

Building Linux golden images on a Linux host is the easy case. Building Windows Server images on a Linux host feels like it should be harder than it is — but it is a well-trodden path, and every piece of it is open source or freely available. Here is how the parts fit together.

The base is an ISO, not a cloud image

Unlike Linux, where you start from an official cloud image, a Windows Server build starts from the installation ISO — for evaluation, from the Microsoft Evaluation Center. That means the build genuinely installs the operating system, which is most of why a Windows build takes 60 to 120 minutes where a Linux build takes 15 to 30. There is no shortcut here; a Windows install takes as long as a Windows install takes.

virtio drivers: the thing Windows does not ship

QEMU/KVM presents virtualized hardware — disk and network — through the virtio interface, which is efficient but not something a stock Windows ISO knows about. Boot Windows Setup against a virtio disk with no driver and it simply will not see a disk to install onto.

The fix is the virtio-win driver ISO, published by the Fedora project. You mount it as a second CD-ROM alongside the install ISO, and Windows Setup can load the storage driver from it during installation. This is the single most common reason a first Windows-on-KVM build fails: the disk “isn’t there” because the driver for it hasn’t been loaded.

autounattend.xml: installing without a human

A normal Windows install asks questions — language, disk, product key, administrator password. A build cannot sit and click through them. Windows Setup looks for an answer file named autounattend.xml on removable media, and if it finds one, it runs the whole installation from it: partitioning, edition selection, the initial administrator account, and a first-logon command list.

You provide it on a small secondary image (a virtual floppy or an extra ISO). Getting the answer file right is fiddly the first time — the disk-configuration section in particular is unforgiving — but once correct it is reusable across builds.

Cloudbase-Init: the Windows answer to cloud-init

Here is the trap that produces a fleet of broken machines. If you install Windows, configure it, and snapshot it as-is, every instance launched from that image is identical — same hostname, same administrator password, same machine SID considerations. That is not a golden image; it is a cloning accident.

On Linux, cloud-init personalizes each instance at first boot. The Windows equivalent is Cloudbase-Init, and it does the same job: on first boot it sets the hostname, configures the administrator credentials, applies user data, and generalizes the instance so it is genuinely its own machine. You install it near the end of the build and leave it in the image. Stripping it out to make the image “cleaner” is precisely how teams end up with a fleet of identically-named servers fighting over the same identity.

From installed disk to AMI

Once the install has finished and Cloudbase-Init is in place, you have a QCOW2 disk. Publishing it to AWS is the same path as any other image: convert to a supported format and import.

qemu-img convert -f qcow2 -O raw windows-server.qcow2 windows-server.raw

From there it is upload-to-S3 and aws ec2 import-image, exactly as for a Linux disk — we walked through that path, IAM role and all, in Converting a QCOW2 image to an AWS AMI.

Two Windows-specific points matter at import:

  • Boot mode. Recent Windows Server expects UEFI. Set --boot-mode uefi explicitly rather than trusting inference.
  • It is a one-way door. AWS applies Windows licensing during import, and the resulting image cannot be exported back out of EC2. Build Windows once, publish outward to each destination you need, and do not plan to move it cloud-to-cloud afterward.

Hardening applies here too

Windows Server has its own CIS Benchmarks and DISA STIGs, and “it’s Windows” is not an exemption from producing an SBOM or a CVE scan. The hardening tooling differs from the Linux OpenSCAP path — Windows uses its own configuration mechanisms — but the obligation is identical: a hardened image, evidence of the hardening, and a signature over the result.

The honest summary

None of these steps is exotic, and all of them are documented. What makes Windows image-building painful is not any one piece — it is that there are a dozen pieces, each with a failure mode that gives you almost nothing to diagnose from, and the feedback loop is an hour long because that is how long the install takes. Getting it wrong at minute 90 and starting over is a real cost.

That is the case Primcoat is built for: the virtio drivers, the answer file, Cloudbase-Init, the hardening, and the conversion are handled as a pipeline, so a Windows Server image is a configuration you fill in rather than an hour-long process you supervise and occasionally restart. The mechanics above are worth knowing — but they are worth automating even more.

Machine-readable:/blog/windows-server-ami-on-linux.md

Get started now.

Request access, describe the image you want, and have your first hardened image in about 15 minutes — a typical estimate, before publishing to your clouds. Primcoat builds, hardens, scans, signs, and publishes it, on the operating systems you already run.