In Part 2 , I got a basic proof-of-concept running: a single headless microVM booting a minimal Debian kernel and forwarding Firefox back to my daily-driver desktop (“Viewer VM”) over VSOCK using Waypipe and PipeWire. It proved the concept, but it was essentially a static, single-instance test rig. To actually live in this setup like I used to in Qubes OS, I needed to turn this prototype into a scalable, multi-domain system. In this post, I’ll walk through the next iteration of the architecture: building a centralized VM lifecycle manager, isolating VMs under dedicated host users, scaling dynamic TAP networks, and running the Waypipe viewer inside a confined nested compositor container. 1. Domain Modeling & Host VM Management In Qubes OS, workloads are categorized into Disposable VMs (DispVMs) for ephemeral tasks and AppVMs for persistent user data, both derived from centralized Template VMs . While Qubes relies on Template VMs to maintain packages across domains, I chose ...
I decided to take the plunge into micro VMs. My goal? To set up a headless micro VM capable of running graphical programs remotely. As a first milestone, I wanted to get Firefox running and smoothly playing videos. (See Part 1 for a breakdown of why I passed on other isolation methods.) Overview At a high level, the concept is simple: I click an icon, and Firefox opens seamlessly on my screen while actually running securely in a VM. This setup is similar to disposable VMs in Qubes OS. When the program closes, the VM is destroyed, leaving absolutely zero trace on the disk. To pull this off, I needed to boot a micro VM with a minimal kernel and disk image, and seamlessly forward both graphics and audio to my daily-driver main VM. The Kernel Unlike standard VMs, micro VMs do not support PCI devices. Instead, they rely on different protocols (like virtio_mmio and virtio_blk ), which the kernel must support natively. Crucially, these drivers must be compiled directly into the kernel...