VMs

Create and manage Firecracker-backed Linux VM services.

VM payloads create long-lived Linux guests managed by yeet. They are useful when a workload needs a full guest OS or stronger isolation than a container.

The official VM catalog is loaded from yeet-vm-images at runtime. Use yeet vm images catalog to see the supported vm://... families for the selected catch host. Examples include:

  • vm://ubuntu/26.04 for Ubuntu 26.04.
  • vm://nixos/26.05 for NixOS 26.05.

Official images include the guest pieces yeet expects for normal workflows: SSH, rsync for yeet copy, yeet metadata integration, and terminal support for TERM=xterm-ghostty.

Create a VM

svc networking is the default for VM payloads:

yeet run <vm> vm://ubuntu/26.04
yeet ssh <vm>

To create a NixOS VM instead, use the NixOS payload:

yeet run <vm> vm://nixos/26.05
yeet ssh <vm>

yeet run creates the VM service. It is not the update path for an existing VM with the same name. To change CPU, memory, disk size, or networking after creation, stop the VM and use yeet vm set.

Use lan when the VM should request an address on your LAN through DHCP:

yeet run <vm> vm://ubuntu/26.04 --net=lan
yeet ssh <vm>

For LAN-only VMs, yeet ssh <vm> connects directly to the guest's LAN IP. lan is the catch host's LAN, not necessarily your workstation's LAN. When you want a VM to appear on the host LAN but still keep a catch-managed fallback, use both networks:

yeet run <vm> vm://ubuntu/26.04 --net=svc,lan
yeet ssh <vm>

With svc, yeet ssh <vm> proxies through catch to the VM's private management IP. With svc,lan, yeet uses the LAN IP when your workstation can reach it and falls back to the catch proxy when it cannot. Use yeet ssh --force-proxy <vm> to force the proxy path for a VM that otherwise would be reached directly. In svc,lan mode, the VM uses the LAN interface as its default route for normal outbound traffic while keeping the service network for yeet-managed names and management access.

VMs with a svc interface use yeet DNS by default. From the guest, other services and VMs on the service network resolve by short name, such as web, or by fully qualified *.yeet.internal names, such as web.yeet.internal. For svc,lan VMs, the yeet DNS link is scoped to yeet names so the LAN interface can still provide DNS for normal external lookups. See DNS for the resolver address, record behavior, and how VM names map to svc management IPs.

Override the default shape when needed:

yeet run <vm> vm://ubuntu/26.04 --cpus=4 --memory=4g --disk=128g

Change an existing VM

Stop a VM before changing CPU, memory, disk size, or networking:

yeet stop <vm>
yeet vm set <vm> --cpus=6 --memory=6g
yeet vm set <vm> --disk=128g
yeet vm set <vm> --net=lan
yeet start <vm>

CPU and memory changes update the Firecracker config used on the next start. Disk changes are grow-only: yeet expands the raw disk file or ZFS ZVOL, runs an ext4 check, and grows the root filesystem. Shrinking disks and live resize are not supported.

Network changes replace the VM's network interfaces while the VM is stopped. Use --net=svc, --net=lan, or a comma-separated list such as --net=svc,lan. For LAN networking, --macvlan-parent, --macvlan-vlan, and --macvlan-mac follow the same rules as VM creation.

For VLAN-tagged LAN networking, pass --net=lan --macvlan-vlan=<id>. yeet uses standard Linux VLAN and bridge devices: it creates its own VLAN path when it can, or uses an existing Linux bridge for that VLAN if the host already has one.

Host requirements

VM payloads require a Linux catch host with KVM available. During yeet init, catch checks for KVM, TUN/TAP, and required VM tooling such as qemu-img, zstd, e2fsck, resize2fs, mount, umount, and ip. On Debian/Ubuntu hosts with the required VM devices available, use yeet init --install-vm-tools root@<machine-host> to install missing VM packages.

ZFS is optional unless you create VMs with --zfs. See ZFS for the shared dataset and snapshot model.

ZFS-backed VM disks

yeet run <vm> vm://ubuntu/26.04 --service-root=tank/vms/<vm> --zfs

For ZFS-backed VMs, the first VM created on a pool for an image version prepares a shared image base on that pool. Later VMs on the same pool and image version clone that shared base instead of writing the root filesystem again.

Use ZFS-backed VMs when you want fast repeated VM creates on the same pool or storage-level VM disk management. Raw VM disks still work without ZFS.

Growing a ZFS-backed VM disk grows the VM ZVOL and then the guest ext4 filesystem. yeet vm set <vm> --disk=<size> still requires the VM to be stopped and still refuses shrink requests.

VM snapshots and restore

ZFS-backed VMs use the same recovery point lifecycle as other ZFS-backed services. Use yeet snapshots create <vm> to create manual VM recovery points:

yeet snapshots create <vm>
yeet snapshots create <vm> --comment "before package upgrade"
yeet snapshots create <vm> --full --comment "checkpoint before risky change"

The default command snapshots the VM ZVOL. If the VM is running, catch pauses the Firecracker VM, snapshots the ZVOL, then resumes it. --full also writes Firecracker state and memory checkpoint files for advanced recovery workflows. Manual VM snapshots require snapshots to be enabled for the VM service. --full is VM-only and requires the VM to be running.

Use the top-level snapshot commands to find and inspect VM disk recovery points:

yeet snapshots list <vm>
yeet snapshots inspect <vm> <snapshot>

Clone a VM disk snapshot when you want to inspect the recovered disk through a separate stopped VM service before changing the original:

yeet snapshots clone <vm> <snapshot> <new-vm>
yeet info <new-vm>

Restore the original VM disk in place with disk mode:

yeet snapshots restore <vm> <snapshot> --mode=disk --stop --yes

--mode=disk is the default. If the VM is running, pass --stop so yeet can stop it before disk restore. Add --start when the VM should start again after the disk restore succeeds.

For a full checkpoint, restore the same recovery point with --mode=full:

yeet snapshots restore <vm> <snapshot> --mode=full --stop --yes

Full restore resumes the VM from Firecracker state and memory. It is stricter than disk restore: the VM must still use the same zvol path, CPU and memory shape, Firecracker binary, and network device names that were present when the checkpoint was captured.

Manual VM snapshots use the same retention policy fields as other yeet snapshots: --snapshots, --snapshot-keep-last, and --snapshot-max-age. Docker-style snapshot events do not apply to VMs.

Image cache

VM image bundles are cached per catch host.

yeet vm images catalog
yeet vm images
yeet vm images update
yeet vm images update vm://nixos/26.05
yeet vm images prune --dry-run

yeet vm images catalog shows the VM payload names supported by the selected catch host before any image is cached, including official remote catalog families and imported local images. A missing image is downloaded automatically on the first VM create.

yeet vm images shows host cache state. yeet vm images update refreshes official image families from their stable latest manifests; pass a specific payload, such as vm://ubuntu/26.04 or vm://nixos/26.05, to refresh only that family. Refreshing the cache picks up new image versions for future VM creates, does not rewrite existing VM disks, and automatically removes old unreferenced image versions when it is safe. When creating a VM with a stale cached image, interactive runs prompt by default; non-interactive runs require --image-policy=update or --image-policy=cached.

yeet vm images prune --dry-run shows what cleanup would remove. Run yeet vm images prune to review the same plan and confirm removal, or add --yes to skip the prompt.

Local VM images

Import a local rootfs bundle onto a catch host, then run it by name:

yeet vm images import lab/ubuntu ./dist/my-vm
yeet run devbox vm://lab/ubuntu
yeet vm images rm lab/ubuntu --yes

A local bundle is a directory containing rootfs.ext4 or rootfs.ext4.zst. If the directory also contains a yeet VM manifest.json, yeet preserves the guest boot capability metadata from that manifest. Rootfs-only bundles use yeet's managed kernel and Firecracker from the current Ubuntu VM image. To test a local kernel, include vmlinux in the bundle and import with --allow-local-kernel:

yeet vm images import kernel/test ./dist/my-vm --allow-local-kernel

Imported image names are catch-host global. Re-importing the same name updates the ref for new VMs; existing VMs keep the exact imported content version they were created with.

For non-Ubuntu custom images, include a manifest that declares fields such as default_user, guest_system_init, and metadata_driver. NixOS bundles should use metadata_driver: "nixos" so yeet writes data under /etc/yeet-vm and lets the guest's NixOS module own system configuration. The default user must be a valid Linux user name, guest_system_init must be an absolute path without spaces or .., and metadata_driver must be ubuntu or nixos.

Custom images own their guest userspace. Install and configure the pieces you want yeet workflows to use: an SSH server that accepts yeet-managed authorized_keys, rsync for yeet copy, and terminal definitions such as xterm-ghostty when your operators use Ghostty or another terminal with a specific TERM value.

Boot and readiness

When yeet run starts a VM, it waits for the guest to report SSH readiness and an IPv4 address before printing the next yeet ssh command.

yeet ssh <vm>
yeet vm console <vm>

Use yeet ssh <vm> for an interactive guest shell. Use yeet vm console <vm> for serial output and boot diagnostics. For yeet-managed VM aliases in ~/.yeet/known_hosts, yeet ssh <vm> repairs a stale host key and retries once after a VM is recreated. Yeet does not edit normal ~/.ssh/known_hosts entries.

Detach from an active console by pressing Enter, then typing ~.. The VM keeps running.

Before opening a VM SSH session, yeet prints the selected path to stderr, such as proxying through the catch host or connecting directly to the guest LAN IP.

Copy Files

Use yeet copy with a VM endpoint to sync files into or out of the guest:

yeet copy ./app devbox:~/app
yeet copy ./configs/*.yml devbox:~/configs/
yeet copy devbox:"/var/log/*.log" ./logs/
yeet copy devbox:/var/log/cloud-init.log ./logs/
yeet copy --force-proxy ./configs/ devbox:~/configs/

VM copy uses rsync over the same direct or proxied SSH path as yeet ssh. Multiple sources and quoted guest globs follow rsync conventions, so use a directory destination such as devbox:~/configs/ or an existing local directory.

Ubuntu VMs default to the ubuntu user. NixOS VMs default to the nixos user. Both have passwordless sudo in the official images.

Ubuntu metadata injection writes yeet-managed .profile and .bashrc blocks for the default user, including ~/.local/bin on PATH, XDG_RUNTIME_DIR when systemd creates it, and color-friendly Ubuntu shell behavior. User content outside the managed blocks is preserved.

NixOS metadata injection is data-only: yeet writes host name, authorized keys, and network files under /etc/yeet-vm, and the NixOS module in the image owns the systemd, user, sudo, SSH, and networking configuration. Use normal NixOS configuration and nixos-rebuild for guest changes.

Kernel and init

Official VM images use a yeet-managed Firecracker kernel and init shim. Guest package upgrades do not manage the boot kernel, bootloader, initrd, or init shim. Updating that boot path comes from a newer yeet VM image bundle.

The official images include built-in TUN, IPv6, nftables, conntrack, conntrack marks, and NAT/masquerade support, plus firewall userspace tools, so guest-installed router and VPN services can manage their own firewall and routing state. Tailscale is not preinstalled.

The fast Ubuntu VM image does not support snap packages. Use container payloads for workloads that need snap-like packaging behavior. NixOS VMs should be customized the Nix way through NixOS modules and nixos-rebuild.

Cleanup

yeet rm <vm>
yeet rm --clean-data <vm>

Use --clean-data when you want to delete the guest disk too. For ZFS-backed VMs, cleanup removes the VM clone and service data, not the shared image base.

  • Installation covers host bootstrap.
  • ZFS covers dataset-backed roots, snapshots, and VM disk clones.
  • Networking covers svc, lan, and ts.
  • Workflows has a compact VM workflow.
  • yeet CLI lists VM flags and commands.