Self-hosted service
hectorm/docker-qemu-win2000 avatar
hectorm/docker-qemu-win2000

docker-qemu-win2000: Windows 2000 in a container, driven over RDP or noVNC

A Docker image for Windows 2000 Advanced Server with SP4.

882 stars51 forksMakefileMIT

At a glance

What is it?
This project packages Windows 2000 Advanced Server with SP4 into a QEMU image that runs inside Docker, with the disk exposed on a named volume and the guest reachable over RDP, VNC, a browser based noVNC console or a shell inside the container. It is a demonstration and preservation artefact rather than a production base, and the README says so with unusual bluntness.
Who is it for?
docker-qemu-win2000 fits a developer who needs a throwaway legacy Windows environment to reproduce an old bug, to demonstrate something that has to run on a 2000 era machine, or to keep a preservation copy of software that will not run on anything current.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Makefile, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the container actually is

The project description is one sentence: a Docker image for Windows 2000 Advanced Server with SP4. The README adds that the instance can be accessed in four different ways, and that the contents of the /mnt/ directory in the container are exposed on the Z: drive via SMB.

So this is not a Windows container in the Docker sense, with a Windows kernel underneath. It is a Linux container running QEMU, and the QEMU process is running a Windows 2000 guest. That distinction matters for everything about how you use it. There is no Windows container runtime involved, the image is a Linux image, and the guest operating system lives entirely inside the emulated machine with its own filesystem, its own driver model and its own idea of hardware.

The /mnt/ to Z: drive mapping is the detail that makes the arrangement practical. QEMU serves that directory to the guest over SMB, so a file you drop into /mnt/ on the Linux host appears as a network drive inside Windows 2000. For a legacy application whose installer you need to run and whose output you need to get back, that is the mechanism that replaces a disk image workflow.

The README shows a desktop screenshot, which is a hint about the intended experience. This is a machine with a GUI, not a headless command prompt, and the whole design of the image is aimed at making that desktop usable from a browser or a remote desktop client on your own workstation.

The repository layout backs the packaging story. There is a Makefile as the primary language, a Dockerfile.m4 template, a config directory, a data directory, scripts, a run.sh and an xfreerdp.sh. The m4 template is the interesting piece, because it is how a single Dockerfile becomes several architecture specific ones, which the Makefile variables then build separately.

Four ways in, and the credentials are printed in the README

The access section lists what the running instance offers, and it is worth reading for the security implications as much as for the convenience.

RDP is on 3389/TCP with user Administrator and password password. VNC is on 5900/TCP and, in the documentation's own words, without password. noVNC is on 6080/TCP at the path vnc.html, which is a browser based console. And there is a shell into the container itself with docker exec, which the documentation offers as docker exec -it qemu-win2000 vmshell.

The default Administrator password being the literal word password is not surprising for a 2000 era image, and it is not the project's doing, since the disk image comes from a third party. What matters is that every port is published to 127.0.0.1 in the run command, which is the correct default and the reason this is not an immediate security problem.

The run command is the whole quick start, and it is worth reading closely because each flag is doing a specific job:

sh
docker run --detach \
  --name qemu-win2000 \
  --stop-timeout 30 \
  --device /dev/kvm \
  --publish 127.0.0.1:3389:3389/tcp \
  --publish 127.0.0.1:5900:5900/tcp \
  --publish 127.0.0.1:6080:6080/tcp \
  --mount type=volume,src=qemu-win2000-disk,dst=/var/lib/qemu/disk/ \
  docker.io/hectorm/qemu-win2000:latest

The stop-timeout of 30 seconds is there because QEMU needs time to shut the guest down cleanly rather than having the container killed underneath it, which would leave the disk volume in an inconsistent state. The named volume for the disk is the other thing that matters, because without it every container start would begin from a pristine image and you would lose the installed software immediately.

The note underneath is the one to internalise. The --device /dev/kvm option can only be used on Linux hosts, and it can be removed on Windows and macOS hosts at a significant performance penalty.

KVM is the difference between usable and theoretical

The environment variables section is short, and it is the part that determines whether the container is any good to work with.

VM_CPU is the number of cores the VM is permitted to use, 2 by default. VM_RAM is the amount of memory the VM is permitted to use, 512M by default. VM_KEYBOARD is the VM keyboard layout, en-us by default. And VM_KVM starts QEMU in KVM mode, true by default, with a note that the --device /dev/kvm option is required for that variable to take effect.

That last note is the kind of detail that saves an afternoon. Setting VM_KVM to true does nothing without the device flag on the host, because KVM acceleration is a kernel interface, and the container has to be given access to it. The default of true is therefore slightly misleading on a host where the flag has been omitted, in that the variable is set but has no effect.

The performance point is not incidental either. A Windows 2000 guest without hardware virtualisation runs entirely under emulation, where every guest instruction is translated by QEMU on the CPU, and the same documentation says that removing the KVM device on Windows and macOS hosts costs a significant performance penalty. For a guest running a 2000 era application this is usually survivable, since the workloads are small, but for anything that installs a large package or does a lot of disk work it is the difference between minutes and hours.

The 512 megabyte default is also period appropriate, and the 2 core default is modest. Both are adjustable through the environment variables, which is the mechanism the image provides for fitting a guest to the machine you have rather than the other way around.

The Makefile builds a different image for every architecture

The Makefile is where the engineering of this project lives, and it is a good example of a build that is mostly about generating the right artefacts rather than about compiling anything.

The image identity is assembled from variables, with the registry as docker.io, the namespace as hectorm and the project as qemu-win2000. The version is then derived from git, and the logic is careful about dirty trees. If the working directory is clean, the version is the first git tag pointing at HEAD, sorted by version refname, falling back to the short commit hash and then to nil. If the tree is dirty, the version becomes the current branch name with a -dirty suffix, or nil.

That is a detail worth pausing on, because it means an image built from an untagged working tree is named after the branch, and an image built from a tagged commit is named after the tag. The release tags follow the same convention, with v18 from 2023-01-29, v19 from 2024-07-28 and v20 from 2026-10-18, and the image is pushed to the Docker Hub repository hectorm/qemu-win2000, which is also the project home page.

The artefact matrix is generated rather than hardcoded. There is a native Dockerfile and tarball, an amd64 Dockerfile and tarball, and an arm64v8 Dockerfile and tarball, all built from the same Dockerfile.m4 template through m4, with the tarballs named after the project and architecture using the .tzst suffix. The variables for docker, git and m4 are all resolved with command -v and the shell is /bin/sh with -euc flags, so a missing tool fails the build rather than producing something wrong.

The build also sets DOCKER_BUILDKIT to 1 and BUILDKIT_PROGRESS to plain, and .DELETE_ON_ERROR is set, which is a Make feature that removes the target file if the recipe fails. For a build that produces a container image from a template, that is the difference between a failed build and a half-written artefact.

The disclaimer is unusually direct, and it should shape your expectations

Two parts of the README deserve to be read in full rather than skimmed, because they determine whether you can use this for what you came for.

The first is the Why section, which is a quotation. Your scientists were so preoccupied with whether or not they could, that they didn't stop to think if they should, attributed to Dr. Ian Malcolm. It is a joke, and it is a joke about exactly what this project is: a demonstration that something technically possible can be done, whether or not it should be.

The second is the disclaimer, and it is the part that determines whether you can use this for what you came for. This project is not affiliated with and has not been approved by Microsoft. The Windows 2000 Advanced Server disk image used in this demonstration has been obtained from WinWorld and it is published for digital preservation and demonstration purposes only.

So the code is MIT licensed, with the licence in a LICENSE.md file, and the guest operating system inside the image is not the project's to license. The project is explicit that the disk image is included for preservation and demonstration. If your use is neither of those, the image is not something the project author can authorise for you, and that question is a legal one rather than a technical one.

That is a real constraint and it is not a flaw in the project. A Windows 2000 image that Microsoft cannot ship is the only kind that can exist in a public container registry, so the disclaimer is a consequence of the goal rather than a hedge against it.

The README is also honest about the performance cost of losing KVM, and about the credentials on the exposed ports. Combined with the fixed Administrator password and the license position, the sensible reading is that this is a laboratory tool with a clear scope, not a base image for a product.

Where a QEMU Windows image is the wrong answer

Three situations rule it out.

The first is anything you intend to operate. The guest has a fixed Administrator account with a published password, the VNC port is documented as having no password at all, and the whole thing is emulated rather than virtualised unless the host grants KVM. That combination is fine for a demonstration on a laptop and wrong for a service, and the only real fix is not to use this image.

The second is a modern workload. Windows 2000 has no modern TLS stack, no current patch level, and no supported drivers, and the applications that run on it are the reason you would want it rather than the applications you would rather run. If your goal is to run a Windows application, the honest question is whether that application has a modern equivalent, and if it does not, whether a licence to run it in a container is available to you.

The third is if you need reproducibility. The image is built from a disk image hosted elsewhere, the Makefile assembles the Dockerfile from an m4 template, and the resulting container carries a specific guest state that you did not build. That is excellent for exploring a 2000 environment and awkward when you need the same image on three machines six months from now.

There is a fair alternative for the same goal. If what you need is a Windows environment to run a Windows application, an officially licensed Windows container or a licensed virtual machine image gives you the same capability with a supported guest, a real licence and a patch path. The difference in effort is the difference between a demonstration and a deployment, and for anything beyond demonstration the official route is the one that will not need a disclaimer.

Editorial conclusion

docker-qemu-win2000 fits a developer who needs a throwaway legacy Windows environment to reproduce an old bug, to demonstrate something that has to run on a 2000 era machine, or to keep a preservation copy of software that will not run on anything current. It is the wrong base for anything you intend to operate, because the image ships a fixed Administrator account with a known password and the guest is a copyrighted disk image obtained from a third party site for demonstration purposes. Before deploying it, read the disclaimer and confirm the image use is legitimate for your situation, decide whether you need the Windows licence position resolved separately from the code licence, and check whether your host can expose /dev/kvm, since without it the documentation is explicit that the performance penalty is significant.

Frequently asked questions

What is docker-qemu-win2000?

It is a Docker image for Windows 2000 Advanced Server with SP4, running the guest under QEMU inside a Linux container. The instance can be reached over RDP on 3389, VNC on 5900, a browser noVNC console on 6080, or a shell via docker exec -it qemu-win2000 vmshell.

How do I run the Windows 2000 container?

Run docker run --detach with the name qemu-win2000, a stop-timeout of 30, the /dev/kvm device, publishes of 127.0.0.1 on 3389, 5900 and 6080, and a named volume mounted at /var/lib/qemu/disk/, using the image docker.io/hectorm/qemu-win2000:latest. The /dev/kvm device can only be used on Linux hosts.

What environment variables does docker-qemu-win2000 support?

VM_CPU sets the number of cores the VM may use and defaults to 2, VM_RAM sets the memory and defaults to 512M, VM_KEYBOARD sets the layout and defaults to en-us, and VM_KVM starts QEMU in KVM mode and defaults to true, though it requires the /dev/kvm device option to take effect.

How do I get files into the Windows 2000 instance?

The contents of the /mnt/ directory in the container are exposed on the Z: drive via SMB, so a file placed there on the host appears as a network drive inside the guest. The guest also has a named volume mounted at /var/lib/qemu/disk/ for the virtual disk itself.

Is the Windows 2000 disk image in docker-qemu-win2000 licensed?

The disclaimer states that the project is not affiliated with and has not been approved by Microsoft, and that the Windows 2000 Advanced Server disk image was obtained from WinWorld and is published for digital preservation and demonstration purposes only. The project code itself is MIT licensed with the terms in LICENSE.md.

Official sources

  1. hectorm/docker-qemu-win2000 on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/hectorm-docker-qemu-win2000.svg)](https://hysenlabs.com/projects/hectorm-docker-qemu-win2000)

Was this useful?