CLI tool
qemus/qemu avatar
qemus/qemu

qemus/qemu: a Docker container that runs a full VM behind a browser tab

qemus/qemu is an open-source project for practical engineering and operations.

2,142 stars255 forksShellMIT

At a glance

What is it?
The qemus/qemu image packages QEMU, KVM and a web viewer into one container, so a Linux host can boot a guest OS from a single BOOT variable. It is convenient, and it is also a thin wrapper around a lot of host privileges.
Who is it for?
Adopt qemus/qemu if you have a Linux host with /dev/kvm, you want a guest OS reachable at http://127.0.0.1:8006 without hand-writing QEMU arguments, and you accept that the container gets /dev/kvm, /dev/net/tun and NET_ADMIN. Do not adopt it if your only machine is a Mac, a Windows 10 box, or a Linux host without KVM, because the README states Docker Desktop on Linux, macOS and Windows 10 does not provide KVM access to containers.
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 22 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

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

Editorial analysis

What qemus/qemu actually packages

QEMU on its own is a command line program with a very long argument list. qemus/qemu is not a fork of QEMU and it does not patch the emulator. It is a Debian-based container image that installs QEMU, adds a web viewer, and exposes a small set of environment variables that generate the QEMU command line for you. The repository description says it plainly: "Docker container for running virtual machines using QEMU." The audience is people who want a virtual machine on a server they already run Docker on, and who would rather set BOOT=mint than assemble -drive, -netdev and -vnc flags by hand.

The feature list in the README is a list of things QEMU already does, wrapped: KVM acceleration, memory ballooning, USB passthrough, 9p host folder sharing, NAT and macvlan networking, OpenGL and Vulkan graphics, and DRM native contexts for compatible Linux guests. What the project adds on top is the packaging: automatic downloads for a fixed list of Linux distributions, a browser viewer on port 8006, and defaults for CPU, RAM and disk size.

That framing matters when you evaluate it. You are not choosing between QEMU and something else. You are choosing between driving QEMU yourself and letting this image drive it for you.

How the container turns BOOT into a running machine

The data flow is short. The entrypoint reads the BOOT variable. If it holds a known name such as mint or alpine, the container downloads that distribution's image from the project's own source. If it holds a URL, the container downloads that URL instead. If a file is bind-mounted at /boot.iso, /boot.img or /boot.qcow2, the README states that the value of BOOT is ignored and the local file is used.

The README lists the accepted formats: .img and .raw as raw, .iso as optical, .qcow2 as QEMU, .vmdk as VMware, .vhd as VirtualPC, .vhdx as Hyper-V and .vdi as VirtualBox. Compressed variants such as .img.gz, .qcow2.xz and .iso.zip are extracted automatically, which is why the Alpine entry in the size table is only 60 MB.

The Dockerfile shows how the runtime is assembled. It builds from debian:trixie-slim and installs QEMU from a pinned Debian snapshot, with the argument VERSION_QEMU set to 1:11.1.0+ds-2 and DEBIAN_SNAPSHOT set to 20260819T142328Z. UEFI firmware comes from the ovmf-generic package, and there are separate pinned versions for the web viewer, the QMP helper and the VNC layer. On amd64 only, a qemu-render .deb is fetched from the qemus/qemu-render releases. Pinning a snapshot is the right call for reproducibility, and it also means the base packages do not move until someone edits the Dockerfile.

Storage, CPU and RAM are not chosen at image build time. The container writes the disk image under /storage, and DISK_SIZE, RAM_SIZE and CPU_CORES adjust the defaults of 64 GB, 2 GB and 2 CPU cores. The /storage bind mount is the only stateful part; everything else in the container is disposable.

Installing qemus/qemu and booting your first guest

The README gives three install paths: Docker Compose, the Docker CLI, and a Kubernetes manifest applied straight from the repository. The Compose file in the repository is the clearest starting point, and it is reproduced in the README:

yaml
services:
  qemu:
    image: qemux/qemu
    container_name: qemu
    environment:
      BOOT: "mint"
    devices:
      - /dev/kvm
      - /dev/net/tun
    cap_add:
      - NET_ADMIN
    ports:
      - 8006:8006
    volumes:
      - ./qemu:/storage
    restart: always
    stop_grace_period: 2m

Save that as compose.yml and run `docker compose up -d`. The container downloads Linux Mint, which the README's table lists at 2.8 GB, so the first start is dominated by that download rather than by boot time. When it finishes, open http://127.0.0.1:8006/ in a browser and complete the installation in the web viewer.

The CLI form is equivalent and useful for a quick trial:

bash
docker run -it --rm --name qemu -e "BOOT=mint" -p 8006:8006 --device=/dev/kvm --device=/dev/net/tun --cap-add NET_ADMIN -v "${PWD:-.}/qemu:/storage" --stop-timeout 120 docker.io/qemux/qemu

Three things in that command are not optional in practice. /dev/kvm is the hardware acceleration path. /dev/net/tun plus NET_ADMIN is what the networking modes need. The /storage mount is where the disk lives, so pointing it at a temporary directory means losing the guest on restart.

To grow the disk later, add an environment variable and restart:

yaml
environment:
  DISK_SIZE: "128G"

The README notes this can resize an existing disk upward without data loss, but the extra space appears as unallocated and must be extended inside the guest. That is a real second step, not a formality.

The host requirements rule out more machines than the feature list suggests

The requirements section is the most important part of the README and the easiest to skim past. It asks for Docker or Podman on a Linux host with KVM support, or Docker Desktop or Podman Desktop on Windows 11 with nested virtualization enabled. Then a note states that Docker Desktop on Linux, macOS and Windows 10 does not currently provide KVM access to containers and is therefore not supported.

Read that against the related searches people run, such as how to use QEMU on Windows or QEMU GUI Windows. On Windows 10, or on any Mac, this image is the wrong tool, and the failure will not look like a clean error message about virtualization. It will look like a container that starts without acceleration or refuses to boot. If you are on macOS, you need a Linux host with KVM somewhere else, or a different approach entirely.

Two more constraints follow from the design. First, the container is privileged in the ways that matter: it takes /dev/kvm, /dev/net/tun and NET_ADMIN. Anyone who can reach port 8006 can operate a machine that has those. The README does not describe authentication in front of the web viewer, so exposure beyond localhost is a decision you make, not one the project makes for you.

Second, the guest list is Linux only. The README answers "How do I boot Windows?" by pointing at dockur/windows instead, because that project includes the drivers Windows needs during installation. For ARM64 guests it points at qemus/qemu-arm. Neither of those substitutions is automatic.

9p file sharing and audio are the two features worth testing early

Host folder sharing uses 9p, and the README is explicit that the guest must have 9pfs support compiled in or available as a kernel module. If it does not, the mount simply fails. The host side is a volume entry:

yaml
volumes:
  - ./example:/shared

Inside the guest, the README gives this command:

shell
mount -t 9p -o trans=virtio shared /mnt/example

After that, ./example on the host appears as /mnt/example in the guest. The dependency on guest kernel support is the part people miss. A minimal or unusual guest image may not have it, and the fix is on the guest side, not in the Compose file.

Audio is off by default and the README says why: the stream is only active while the option is enabled, so it costs no bandwidth otherwise. Turn it on with AUDIO set to Y, then enable Audio under Settings, Advanced in the web viewer. If you set the variable and hear nothing, the second step is the one you skipped.

Both of these are good first tests after installation. They exercise the guest kernel, the virtio transport and the viewer in one pass, and they surface problems while the machine is still disposable.

How it compares with running QEMU directly or using libvirt

The honest alternative is QEMU itself, invoked from a shell or from a systemd unit. That path gives you every flag, every device model and every firmware option, and it does not require a container runtime at all. The cost is that you own the argument list, the disk image creation, the firmware selection and the networking setup. qemus/qemu trades that control for a BOOT variable and a browser tab. If your guest needs a device or a machine type the wrapper does not expose, you are back to writing QEMU arguments, and the container is then only adding a viewer.

The second alternative is libvirt with virsh or virt-manager on the same Linux host. libvirt is a management layer with a persistent definition per domain, storage pools, and a stable API that other tools build on. qemus/qemu has no persistent domain definition; the configuration lives in environment variables in a Compose file, and the state lives in the /storage directory. For one or two long-lived machines that is simpler. For a fleet where you want to query and reconcile domain state, libvirt is the more appropriate layer, and it does not need a container to hold it.

A third option is running QEMU inside a container by hand, with your own Dockerfile. That is essentially what this project is, minus the download table, the viewer and the pinned snapshot. The pinned Debian snapshot is the part most people would not bother to reproduce, and it is the part that makes rebuilds predictable.

Maintenance, upgrades and what the MIT licence does not cover

The repository is not archived, and the last push was on 2026-08-27, the same day as the v7.49 release. The two preceding releases, v7.48 and v7.47, landed on 2026-08-21 and 2026-08-19, so the release cadence in that window was fast. That is a fact about the repository, not a promise about the next six months.

Upgrade cost is low in one direction and not in the other. Pulling a newer image and restarting the container is cheap, because the guest disk lives in /storage and is not part of the image. But the image pins QEMU, OVMF, SeaBIOS and several helper components to specific versions, so an image upgrade can move the emulator underneath a guest that is already installed. There is no documented rollback procedure in the README for returning to a previous image tag, and no documented migration step for a guest created under an older QEMU. Take a copy of the /storage directory before you pull.

The licence situation has two layers. The repository's own code is MIT, which is permissive and places few conditions on reuse. The container also redistributes QEMU and firmware packages built from Debian, and those carry their own licences, including the non-free component the Dockerfile enables for the trixie repository. If you redistribute the image or ship it inside a product, the obligations you need to check are the ones attached to the bundled components, not the MIT text at the top of this repository. That is a question for your own legal review, not something the README settles.

Editorial conclusion

Adopt qemus/qemu if you have a Linux host with /dev/kvm, you want a guest OS reachable at http://127.0.0.1:8006 without hand-writing QEMU arguments, and you accept that the container gets /dev/kvm, /dev/net/tun and NET_ADMIN. Do not adopt it if your only machine is a Mac, a Windows 10 box, or a Linux host without KVM, because the README states Docker Desktop on Linux, macOS and Windows 10 does not provide KVM access to containers. Do not adopt it for Windows guests either; the README points those users at dockur/windows. Before you commit, check that /dev/kvm exists on the host, decide whether the storage bind mount points at a local disk or a network share, and confirm which BOOT value you want, since the image downloads that operating system on first start.

Frequently asked questions

What is qemus/qemu and what is it used for?

It is a Docker container image that runs virtual machines with QEMU and exposes a web-based viewer on port 8006. The README describes it as a container for running virtual machines using QEMU, with automatic downloads for a list of Linux distributions.

Which is better, VirtualBox or qemus/qemu?

The README does not compare the two, so the only difference it states is the deployment model: qemus/qemu runs as a container on a Linux host with KVM and is controlled through a browser, while it lists no VirtualBox integration at all. For guests it does not cover, such as Windows, the README points to other projects rather than to VirtualBox.

Is qemus/qemu safe to use?

The README does not make a security claim. What it does show is the privilege the container requests: /dev/kvm, /dev/net/tun and the NET_ADMIN capability, plus a web viewer on port 8006 with no authentication step described.

Can I use qemus/qemu to install Windows 11?

No. The README answers the question about booting Windows by directing users to dockur/windows, which it says includes the drivers required during installation.

Official sources

  1. Official README
  2. Project repository
  3. Release notes
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/qemus-qemu.svg)](https://hysenlabs.com/projects/qemus-qemu)