QEMU VM Controller (or qcontroller
) is a flexible, API-driven tool for managing QEMU-based virtual machine instances on Linux and macOS. It is designed for users who need precise control over VM networking, image management, and orchestration—whether for local development, testing, or reproducible infrastructure setups.
qcontroller
provides a unified interface for four primary VM operations:
- Launch – Create and optionally start a new VM from a known image.
- Start – Resume a stopped VM.
- Stop – Gracefully or forcefully stop a running VM.
- Info – Query the status and configuration of a VM.
Operations are defined using Protocol Buffers and exposed via both gRPC and a RESTful HTTP gateway, making integration with scripts, dashboards, or automation frameworks straightforward.
- 🛠 Single static binary: All logic is bundled into one Go binary with multiple subcommands.
- 🖥 Cross-platform support: Works on Linux and macOS (Intel tested; Apple Silicon supported via QEMU).
- 🧠 Declarative VM descriptions: Define VM specs via JSON configs matching Protobuf definitions.
- 📡 gRPC + REST API: Communicate via a structured protocol or plain HTTP—your choice.
- 📦 Custom image support: Upload and manage your own VM images via API.
- 📜 Auto-generated OpenAPI schema: Serves interactive API docs using http-swagger.
- 🧩 Easily extendable: Add support for snapshots, cloning, or additional QEMU flags with minimal effort.
To build the binary, run:
make install-tools
make
The compiled binary provides the following subcommands:
qemu
– Thin wrapper for the QEMU system binary; handles actual VM process execution.controller
– Manages VM lifecycle and communication via gRPC.gateway
– Exposes REST endpoints mapped from gRPC via gRPC-Gateway.
Separation of Controller and QEMU: It's important to note that the application was split into two components: the controller and QEMU. This separation was necessary because the qemu command requires elevated privileges due to its use of networking features such as TAP on Linux and vmnet on macOS. To avoid granting elevated rights to the entire application, a minimal QEMU service was created. This service runs as root and is responsible solely for executing the qemu command. The controller, on the other hand, manages the virtual machine lifecycle and runs as a non-root user, ensuring a more secure and controlled execution environment.
Running the App
Each subcommand expects a JSON configuration file matching its Protobuf definitions.
All subcommands must run concurrently; orchestration (e.g., via systemd
on Linux) is recommended. A startup script is provided to run all required components together
bash start.sh -h
This command will start all three components:
- ➜ gateway:
http://localhost:8080
- ➜ qemu:
0.0.0.0:8008
- ➜ controller:
0.0.0.0:8009
Then hit the REST API (e.g. using swagger ui, that is hosted at http://localhost:8080/v1/swagger/index.html
):
This repo includes tooling to build a base Ubuntu Cloud image with the QEMU Guest Agent (QGA), compatible with qcontroller's QAPI integration. Use Packer to build it:
packer init .
packer build .
See qga for details on building QGA.
The gRPC gateway automatically generates a Swagger-compatible OpenAPI schema. A basic Swagger UI is served at:
http://localhost:8080/v1/swagger/index.html
All REST endpoints follow the schema defined in /src/protos/.
Use the provided Dockerfile to ensure a consistent dev environment.
To run commands inside the container:
./exec.sh make lint
This wraps the environment with all Go tools and build dependencies preinstalled.
make
git
go
protoc
- Go plugins:
protoc-gen-go
protoc-gen-go-grpc
buf
protoc-gen-grpc-gateway
protoc-gen-openapi
golangci-lint
qemu-system-x86_64
(currently, only x86_64 VMs are supported and tested)
On Linux, a DHCP server is required for automated VM networking (e.g., bridge + TAP). For setup and an example configuration, see dhcp.
Note: DHCP is not bundled with this project to give users the freedom to plug into their existing setup