Running Windows Apps on Linux with Docker: A Complete Guide
This post is written with the assistance of Claude Sonnet 4.5 (Anthropic).
How I got a Windows-only music app running on Ubuntu 24.04 — with audio — using dockur/windows.
Background
I wanted to use Qishui Music (汽水音乐), a music streaming app from ByteDance that only has official clients for Windows, macOS, Android, and iOS. No Linux support. After looking at a few options — the web app, Wine, Waydroid — I ended up going down a more interesting path: running a full Windows VM inside a Docker container using dockur/windows.
How dockur/windows Works
Despite the name, this isn't a true Windows container. It's a QEMU/KVM virtual machine wrapped inside a Docker container. The container shell passes through /dev/kvm to get near-native performance via hardware virtualization. You get:
- A web-based VNC viewer at port
8006for initial setup - RDP access at port
3389for day-to-day use - Automatic Windows ISO download and installation
- Persistent storage via a Docker volume
The architecture looks roughly like this:
Windows VM (QEMU)
↕ QEMU user-mode NAT
Docker container (dockurr/windows image)
↕ /dev/kvm passthrough
Linux host (Ubuntu 24.04 + KVM)
Choosing a Windows Version
dockur/windows supports everything from Windows 2000 to Windows Server 2025. For running a lightweight app like a music player, I went with Windows 10 LTSC 2021 (VERSION: "10l"):
- Smaller download (~4.6 GB vs 7.2 GB for Win11 Pro)
- No TPM 2.0 / Secure Boot requirements that complicate VM setups
- Stripped of bloatware (Cortana, preinstalled UWP apps, etc.)
- Long-term support, minimal forced updates
LTSC removes preinstalled apps but keeps all core system components, fonts, and runtime libraries intact — Office installs fine, for example.
The docker-compose.yml
services:
windows:
image: dockurr/windows
container_name: windows
environment:
VERSION: "10l"
LANGUAGE: "Chinese"
KEYBOARD: "zh-CN"
REGION: "zh-CN"
RAM_SIZE: "8G"
CPU_CORES: "4"
DISK_SIZE: "128G"
USERNAME: "myuser"
PASSWORD: "mypassword"
devices:
- /dev/kvm
- /dev/net/tun
cap_add:
- NET_ADMIN
ports:
- "8006:8006"
- "3389:3389/tcp"
- "3389:3389/udp"
volumes:
- ./windows:/storage
- ./shared:/shared
restart: unless-stopped
stop_grace_period: 2m
A few notes on the config:
restart: unless-stoppedis better thanalwaysfor manual control — if you explicitly stop the container, it won't auto-start on the next Docker daemon restart.stop_grace_period: 2mgives Windows time to shut down cleanly before Docker force-kills it.- The
./sharedvolume maps to aSharedfolder on the Windows desktop, useful for moving files in and out.
Starting it
docker compose up -d
Then open http://localhost:8006 in your browser and watch the automated installation complete. No interaction needed.
Getting the ISO Locally (When Download Fails)
The container downloads the Windows ISO automatically, but this can fail depending on your network. The cleanest workaround is to download the ISO yourself and mount it directly:
volumes:
- ./windows:/storage
- ./Win10_LTSC_2021.iso:/boot.iso # container uses this instead of downloading
When /boot.iso is present, the container skips the download entirely. The official Microsoft site doesn't offer LTSC directly — massgrave.dev is a well-known community resource for genuine Microsoft ISOs.
Connecting via RDP
The web viewer at port 8006 is only meant for the installation phase — low image quality, no audio, no clipboard. For actual use, connect via RDP.
On Linux, use FreeRDP:
sudo apt install freerdp2-x11
xfreerdp /v:localhost:3389 \
/u:myuser /p:mypassword \
/cert:ignore \
/sound:sys:pulse \
/audio-mode:0
This streams the Windows desktop to your local display and routes audio back through PulseAudio.
Getting Audio Working
This took some debugging. The RDP audio pipeline works fine — you can hear system sounds — but Qishui Music was completely silent. Nothing showed up in Windows' volume mixer during playback.
The fix turned out to be embarrassingly simple: run the app as Administrator.
Right-click the app → Properties → Compatibility → check "Run this program as an administrator".
My best guess: the app uses WASAPI in exclusive mode, which requires elevated privileges to access the virtual audio device in a VM environment. On real hardware this works fine; in a QEMU VM it silently fails without admin rights.
Networking Notes
The VM's network goes through QEMU's user-mode NAT — Windows gets an IP like 172.30.0.1 as its gateway, which is entirely virtual and doesn't map directly to anything on the host. This makes proxy configuration non-trivial.
The simplest solution: install a proxy client directly inside Windows and import your subscription/config via the SMB share (\\host.lan\Data). Trying to forward the host's proxy into the VM adds unnecessary complexity.
Auto-start on Boot
With restart: unless-stopped in the compose file, the container starts automatically with the Docker daemon. Make sure Docker itself is enabled at boot:
sudo systemctl enable docker
Resource Usage
On my machine (AMD Ryzen 9600X, 32 GB RAM), with 4 cores and 8 GB allocated to the VM:
CPU: ~126% (≈1.3 cores out of 4 allocated — very light)
MEM: 8.1 GiB / 31 GiB (26%)
Completely comfortable. The VM idles quietly in the background.
Summary
| Step | Solution |
|---|---|
| Run Windows on Linux | dockur/windows (QEMU/KVM in Docker) |
| Windows version | Windows 10 LTSC 2021 |
| ISO download failed | Mount local ISO as /boot.iso |
| Remote desktop | FreeRDP with /sound:sys:pulse |
| No audio in music app | Run app as Administrator |
| Proxy inside VM | Install proxy client natively in Windows |
| Auto-start | restart: unless-stopped + systemctl enable docker |
The whole setup took a few hours of troubleshooting, but the end result is stable: a persistent Windows environment running as a background service, accessible via RDP with audio, using about 26% of system RAM.
Tested on Ubuntu 24.04, AMD Ryzen 9600X, NVIDIA RTX 5060 Ti, 32 GB RAM.