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.04for Ubuntu 26.04.vm://nixos/26.05for 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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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, andts. - Workflows has a compact VM workflow.
- yeet CLI lists VM flags and commands.