Virtualisation

12

QEMU

rawnix runs QEMU fully rootless. Networking is provided by passt — a userspace network stack that requires no privileges and no tun/tap devices. Display is via -display gtk using the Wayland backend.

Installation

# pkg add qemu passt

Your user needs to be in the kvm group for hardware acceleration: usermod -aG kvm username.

Running a VM

# Start passt first
$ passt --socket /tmp/passt-kali.sock &
# Launch VM
$ qemu-system-x86_64 \
    -enable-kvm \
    -m 2048 \
    -cpu host -smp 4 \
    -drive file=kali.qcow2,format=qcow2,if=virtio \
    -netdev stream,id=net0,server=off,addr.type=unix,addr.path=/tmp/passt-kali.sock \
    -device virtio-net-pci,netdev=net0 \
    -device virtio-tablet-pci \
    -device virtio-vga,xres=1920,yres=1080 \
    -display gtk &

Rootless networking (passt)

passt provides NAT networking to QEMU VMs without root, tun/tap, or kernel modules. For an internal network between two VMs (such as Whonix Gateway and Workstation), use a multicast socket:

# Gateway — internal interface (second -netdev)
-netdev socket,id=internal,mcast=230.0.0.1:1234,localaddr=127.0.0.1 \
-device virtio-net-pci,netdev=internal \
# Workstation — same mcast address
-netdev socket,id=internal,mcast=230.0.0.1:1234,localaddr=127.0.0.1 \
-device virtio-net-pci,netdev=internal \
localaddr=127.0.0.1 is required. Without it, QEMU binds the multicast socket to the wireless interface and the VMs cannot see each other.

Clipboard sharing

Clipboard sharing between the rawnix host and QEMU guests uses the qemu-vdagent chardev — the agent protocol without the SPICE display stack. Build QEMU with --enable-gtk-clipboard and add to the launch command:

# Add to QEMU launch flags
-device virtio-serial,packed=on,ioeventfd=on \
-device virtserialport,name=com.redhat.spice.0,chardev=vdagent0 \
-chardev qemu-vdagent,id=vdagent0,name=vdagent,clipboard=on,mouse=off \
# Inside the guest — install and start spice-vdagent
$ systemctl enable --now spice-vdagentd
13

Podman

Podman runs containers rootlessly on rawnix. The runtime stack is podmancrun (OCI runtime) → aardvark-dns + netavark (networking) → catatonit (init). No Docker daemon. No root required.

Installation

# pkg add podman crun aardvark-dns netavark catatonit

The kernel must have user namespaces, cgroups v2, and overlay filesystem enabled — see the Security & sandboxing and Cgroups sections.

Rootless containers

Configure subuid and subgid ranges for your user — required for rootless operation:

# Add to /etc/subuid and /etc/subgid
# echo "username:100000:65536" >> /etc/subuid
# echo "username:100000:65536" >> /etc/subgid
# Initialize the podman user configuration
$ podman system migrate

Running containers

# Run a container
$ podman run --rm -it alpine sh
# Run detached with a name
$ podman run -d --name myapp -p 8080:80 nginx
# List running containers
$ podman ps
# Stop and remove
$ podman stop myapp && podman rm myapp
14

Xen

rawnix supports Xen as a paravirtualised hypervisor for hard VM isolation — each domU runs in its own hardware-enforced trust boundary. The boot path is limine → multiboot2 → xen.gz + vmlinuz. Direct xen.efi EFI boot is not supported on all firmware — limine is the correct and tested bootloader.

dom0 kernel

The Linux kernel running as dom0 requires Xen-specific options. Build the kernel with make LLVM=1 and enable:

CONFIG_XEN=y
CONFIG_XEN_DOM0=y
CONFIG_XEN_PRIVILEGED_GUEST=y
CONFIG_XEN_BALLOON=y
CONFIG_XEN_SCRUB_PAGES_DEFAULT=y
CONFIG_XEN_DEV_EVTCHN=y
CONFIG_XEN_BACKEND=y
CONFIG_XEN_NETDEV_BACKEND=m
CONFIG_XEN_BLKDEV_BACKEND=m
CONFIG_XEN_PCIDEV_BACKEND=m
CONFIG_XEN_GNTDEV=y
CONFIG_XEN_GRANT_DEV_ALLOC=y
CONFIG_SWIOTLB_XEN=y
CONFIG_XEN_FBDEV_FRONTEND=y
CONFIG_XEN_SAVE_RESTORE=y
CONFIG_XEN_ACPI_PROCESSOR=y

Booting with limine

Install limine as BOOTX64.EFI and configure it to load Xen via multiboot2. Place xen.gz and the dom0 kernel on the ESP:

timeout: 5
default_entry: 1
/Xen dom0 rawnix
    protocol: multiboot2
    path: boot():/xen.gz
    cmdline: dom0_mem=6144M,max:6144M dom0_max_vcpus=4 iommu=no noreboot
    module_path: boot():/vmlinuz-6.12.77
    module_cmdline: root=/dev/nvme0n1p6 rw quiet
xen.gz must be on the ESP. Copy it from /boot/xen.gz to /boot/efi/xen.gz after every Xen package update. limine reads from the ESP only.

Xen runit services

Three runit services are required for Xen toolstack operation. All services guard against non-dom0 boots — they exit cleanly if /proc/xen/capabilities does not contain control_d. Do not symlink them into /service/ until after a confirmed first Xen boot.

ServicePurpose
xenstoredXenStore daemon — required first, all other tools depend on it
xencommonsXencommons setup — hotplug and backend services
xenconsoledConsole multiplexer — access domU consoles via xl console
# ln -s /etc/sv/xenstored  /service/
# ln -s /etc/sv/xencommons  /service/
# ln -s /etc/sv/xenconsoled /service/

Creating domUs

domUs are created with xl. A basic PVH domU configuration using a LUKS-encrypted partition:

name = "fedora"
type = "pvh"
memory = 4096
vcpus = 4
disk = [ "/dev/mapper/fedora,raw,xvda,rw" ]
vif  = [ "bridge=xenbr0" ]
bootloader = "pygrub"
# Open LUKS partition first
# cryptsetup open /dev/nvme0n1p9 fedora
# Create and start the domU
# xl create fedora.cfg
# List running domains
# xl list
# Connect to console
# xl console fedora
# Shutdown
# xl shutdown fedora

LLVM musl libc libressl Independent