Virtualisation
QEMU
krypt/sh 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 \
Clipboard sharing
Clipboard sharing between the krypt/sh 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
Podman
Podman runs containers rootlessly on krypt/sh. The runtime stack is podman → crun (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
Xen
krypt/sh 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 krypt/sh
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
/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.
| Service | Purpose |
|---|---|
| xenstored | XenStore daemon — required first, all other tools depend on it |
| xencommons | Xencommons setup — hotplug and backend services |
| xenconsoled | Console 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