A small hypervisor manager for libvirt/QEMU that is managed over SSH.
genesis serve puts a terminal UI in front of KVM, so anyone with an account can spin up virtual machines on a shared host and reach them with nothing but an SSH client.
- Multi-user over SSH:
ssh you@host -p 6777, public-key auth, admin and user roles, per-account quotas. - Cloud images and ISOs from an editable catalog. Each VM boots from a copy-on-write overlay and is provisioned by cloud-init.
- Private NAT network on IPv4 and IPv6. Nothing is reachable from the outside until you publish a port.
- A serial console, a host shell, and an SSH jump into any VM, all from inside the TUI.
- Storage pools across disks, shared folders over virtiofs, offline resize, static IPs, and per-VM resource caps.
Arch Linux, with libvirt etc.:
pacman -S libvirt qemu-desktop dnsmasq edk2-ovmf nftables
systemctl enable --now libvirtdmake # build ./genesis
sudo make install # -> /usr/local/bin/genesis
sudo genesis init # write /etc/genesis/config.yaml
sudo genesis user add elias -key ~/.ssh/id_rsa.pub -role admin
sudo make install-service # systemd or runit (autodetected)Then, from anywhere:
ssh elias@northernsi.de -p 6777The binary only bootstraps and runs the daemon. Everything about VMs lives in the TUI.
| command | what it does |
|---|---|
genesis serve |
serve the TUI over SSH on :6777 |
genesis user |
add or remove accounts, keys, roles |
genesis init |
write a default config |
libvirt owns the VMs. genesis talks to it through the Go bindings. The guest network runs in libvirt's open forward mode and genesis does the firewalling itself:
Two nftables tables (ip genesis, ip6 genesis6) masquerade guest traffic, drop unsolicited inbound, and DNAT the ports you publish.
Domains are q35 with a host-passthrough CPU and virtio disk and net, and a serial console on a pty. BIOS by default; images that need it get OVMF/UEFI with a qcow2 NVRAM.
/etc/genesis/config.yaml holds the SSH listen address, the data directory, the network CIDRs, the image/ISO catalog, and VM defaults. Mutable state (the VM registry and published ports) lives in /var/lib/genesis/state.json.
The TUI server binds every interface on port 6777 by default. Change it with:
ssh:
addr: "" # empty: 0.0.0.0/::
port: 6777