mvmctl docs

mvmctl documentation

Everything you need to install, configure, and manage microVMs with mvmctl. Covers every command with explanations, callouts, and real-world examples.

Before you begin

mvmctl runs on Linux only — Firecracker requires KVM, which is not available on macOS or Windows. Make sure your system meets these requirements before installing.

  • Linux host (x86_64 or aarch64) with KVM support — check with ls /dev/kvm
  • Access to /dev/kvm and membership in the kvm group
  • Python 3.13+ for pip/pipx/source installs
  • Root access once for host setup (mvm init or sudo mvm host init)
  • nftables for NAT and firewall rules (default backend)

System packages

mvmctl depends on a few system tools for networking, image handling, and cloud-init:

Terminal

sudo apt-get install -y iproute2 iptables nftables cloud-image-utils qemu-img e2fsprogs kmod
On Ubuntu 24.04+, you may need --break-system-packages with pip install. Use the binary or pipx install instead.

Install mvm

Four ways to install. The prebuilt binary is the fastest — no Python runtime needed.

No Python runtime required. Best for production machines.

Terminal

curl -L -o mvm https://github.com/AlanD20/mvmctl/releases/latest/download/mvm
chmod +x mvm
sudo mv mvm /usr/local/bin/
mvm --help
After installing, run mvm --help to verify. If "command not found", ensure /usr/local/bin is in your PATH.

Initialize host

Before creating any VMs, your host needs one-time setup: KVM module loading, IP forwarding, the mvm group, sudoers permissions, and bridge networking. This is what mvm init handles for you.

Interactive setup (recommended)

Run mvm init — it walks you through host config (sudo/group/sudoers), Firecracker binary download, cache initialization, service binary extraction, and optional libguestfs setup. Escalates to root automatically when needed.

Terminal

mvm init
When prompted to log out/in, do it. Group membership changes only apply to new login sessions. If you skip this, subsequent commands will fail with permission errors. Alternatively run newgrp mvm to avoid logging out.

Manual host setup

Prefer doing things step by step? sudo mvm host init does the one-time machine setup. It is idempotent — safe to re-run.

Terminal

sudo mvm host init
mvm host init requires sudo because it creates the mvm system group, writes sudoers drop-in files, loads KVM kernel modules, enables IP forwarding, and sets up bridge/TAP networking. Normal mvm commands do not need sudo after this runs.

What host init actually does

  • Loads kvm, kvm_intel/kvm_amd kernel modules (networking modules tun and bridge are loaded as needed)
  • Enables net.ipv4.ip_forward for NAT networking
  • Creates the mvm system group and adds your user to it
  • Writes a sudoers drop-in to /etc/sudoers.d/mvm so mvmctl can run privileged commands (ip, iptables, sysctl, modprobe) without password prompts
  • Sets up the mvm-net bridge and firewall chains for NAT

Other host commands

Terminal

mvm host ls       # Show current host configuration state — useful for verifying setup
mvm host info     # Show host hardware, limits, and VM capacity projection
mvm host info --refresh  # Re-detect hardware and limits before displaying
mvm host info --json     # Output as JSON
mvm host clean    # Remove networking config only (bridges, TAPs, iptables rules)
mvm host reset    # Full rollback — networking, sysctl, sudoers, and the mvm group
mvm host reset is destructive. It removes the mvm group, meaning anyone in it loses mvm access. Only use if you are permanently uninstalling mvmctl.

Create your first VM

This walkthrough takes you from zero to a running microVM: generate an SSH key, download a kernel and OS image, boot the VM, connect, and clean up.

Step by step

Create a complete microVM from scratch: generate an SSH key, download a kernel and OS image, boot the VM, connect, and clean up.

Terminal

# 1. Generate an SSH key for VM access
mvm key create test --default

# 2. Download Firecracker-optimized kernel (~30s)
mvm kernel pull --type firecracker

# 3. Download an Ubuntu 24.04 image
mvm image pull ubuntu --version 24.04

# 4. Create and start the VM
mvm vm create myvm --image ubuntu:24.04

# 5. Wait for cloud-init to finish (~30-60s)
mvm logs myvm --follow

# 6. SSH into the VM
mvm ssh myvm

# 7. List running VMs
mvm vm ls

# 8. Remove the VM when done
mvm vm rm myvm -f
Cloud-init takes 30-60 seconds on first boot. The VM is running during this time — it is just running startup scripts. Watch progress with mvm logs myvm --follow.
You need at least one SSH key set up before creating a VM. Use mvm key create NAME --default or pass --ssh-key explicitly when creating a VM.
Images are several hundred MB. Ensure at least 2 GB free in ~/.cache/mvmctl/.

mvm vm create

Creates and immediately starts a Firecracker microVM. Under the hood mvmctl: (1) copies the root filesystem image to a per-VM directory, (2) generates a Firecracker JSON boot config, (3) picks an available IP from the network lease pool, (4) starts a temporary HTTP server for cloud-init, (5) launches Firecracker (+ jailer). There is no separate "start" command — the VM boots right away.

All flags

Terminal

VM_NAME (positional)          VM name (required). Used to identify the VM in all commands.
--image IMAGE              Image name, type:version (e.g. ubuntu:24.04), short ID, or path to .ext4 file. Auto-detected from defaults if omitted.
--kernel KERNEL            Kernel short ID or path to vmlinux. Auto-detected from defaults if omitted.
--vcpus, --cpus N          vCPU count (default: from user config).
--mem, --memory N          Memory in MiB or GiB (e.g. 512M, 1G) (default: from user config).
--disk-size, -s SIZE       Rootfs disk size (e.g. 1G, 512M or 1024M). Default: from config.
--ssh-key KEY              SSH public key name or path, e.g. 'mykey' or ~/.ssh/id_ed25519.pub
--user USER                Default SSH user for cloud-init. Default: from config.
--ip ADDRESS               Static guest IP, e.g. 172.27.0.42. Default: auto-assigned.
--network, --net NAME      Named network to attach to. Default: 'net'.
--mac ADDRESS              Custom MAC address. Auto-generated if omitted.
--cloud-init-mode MODE     One of: off (default), inject, iso, net.
--user-data PATH           Path to custom cloud-init user-data file.
--nocloud-net-port PORT    Port for nocloud-net HTTP server (0=auto-assign).
--no-pci                Disable PCI transport (default: enabled). Required for hotplug support.
--nested-virt/--no-nested-virt   Enable nested virtualization (requires PCI, adds kvm-intel/amd.nested=1 boot arg)
--cpu-template PATH              Path to CPU template JSON file (merged with nested-virt config if both set)
--no-console               Disable serial console.
--lsm-flags FLAGS          Linux Security Module flags for kernel cmdline.
--firecracker-bin PATH     Path to firecracker binary. Env var: MVM_FIRECRACKER_BIN.
--enable-logging/--no-enable-logging  Enable Firecracker logging.
--enable-metrics/--no-enable-metrics  Enable Firecracker metrics.
--boot-args ARGS           Custom kernel boot arguments (e.g. 'console=ttyS0 reboot=k panic=1').
--skip-cleanup             Skip cleanup on failure (for debugging).
--skip-deblob              Skip debloat operations on rootfs (removes OS caches, package manager caches).
--count, -c N              Number of VMs to create (default: 1).
--atomic                   If any VM fails, remove all successfully-created VMs (all-or-nothing).
--volume, -v NAME          Attach a volume to the VM (can be specified multiple times).

Examples

Minimal — get a default VM running fast

Terminal

# Assuming kernel + image fetched, default key set:
mvm vm create myvm --image ubuntu:24.04

Defaults: 1 vCPU, 512 MiB RAM, auto-assigned IP on network net (172.27.0.0/24).

Custom resources

Terminal

mvm vm create \
  build-vm \
  --image ubuntu:24.04 \
  --vcpus 4 \
  --mem 8192 \
  --disk-size 50G

Useful for CI runners or compiling in isolated environments.

Specific network and static IP

Terminal

# First create a network
mvm network create isolated --subnet 10.0.0.0/24

# Then attach the VM with a fixed IP
mvm vm create myvm --image ubuntu:24.04 --network isolated --ip 10.0.0.50

The IP must fall within the network subnet. Default network net uses 172.27.0.0/24.

Non-root user and custom SSH key

Terminal

mvm key create workstation-key --default
mvm vm create \
  dev-vm \
  --image ubuntu:24.04 \
  --ssh-key workstation-key \
  --user ubuntu

The --user flag sets the cloud-init default user. This user gets password-less sudo inside the VM.

Alpine — lightweight and fast

Terminal

mvm image pull alpine --version 3.21
mvm vm create tiny-vm --image alpine:3.21 --vcpus 1 --mem 256

Alpine boots in seconds. Great for testing or ephemeral workloads.

Custom cloud-init user-data

Terminal

# Write a custom user-data file
cat > my-user-data.yaml << 'EOF'
#cloud-config
package_update: true
packages:
  - htop
  - build-essential
EOF

# Pass it to the VM
mvm vm create myvm --image ubuntu:24.04 --user-data my-user-data.yaml

Custom user-data merges with mvmctl's default cloud-init. You can add packages, write files, run commands, etc.

Batch creation with atomic rollback

Terminal

# Create 5 VMs atomically — if any fails, all are removed
mvm vm create cluster --image ubuntu:24.04 --count 5 --atomic

# With a volume attached to a single VM
mvm volume create shared-data 10G
mvm vm create worker --image ubuntu:24.04 --volume shared-data

The --count flag auto-generates names by appending -1, -2, etc. The --atomic flag ensures no partial creation — all created VMs are rolled back if any single VM fails. --count and --volume are mutually exclusive (a volume can only be attached to one VM). Implicit IP and MAC assignment is used (no --ip or --mac with --count > 1).

Firecracker is not a hypervisor you can "pause" like VirtualBox. mvm vm create starts the VM immediately.
Each VM gets an IP from the lease pool. The default network (net) uses 172.27.0.0/24. Leases are reused when VMs are removed.
The --disk-size flag resizes via qemu-img resize. It only grows the image — shrinking requires manual intervention.
If you do not set --ssh-key and have no default key, the VM will boot but you cannot SSH in. Use mvm console for serial access instead.

VM Lifecycle

Once your VM is created, these commands let you interact with, inspect, snapshot, and tear it down.

mvm ssh

SSH into a running VM by name. Resolves the VM name to its IP address from the lease database and connects with the cached SSH key.

Terminal

mvm ssh myvm

SSH as the default user (root by default unless --user was specified).

Terminal

mvm ssh myvm --user admin

SSH as a specific user.

SSH only works after cloud-init finishes. On first boot, cloud-init generates SSH host keys and configures the default user. This takes 30-60 seconds.
mvmctl automatically passes the correct SSH key and user. You do not need ssh -i commands. But you do need a key set up beforehand.
Works on custom networks too — mvmctl looks up the correct IP from the lease database.

mvm console

Attaches a PTY-based serial console to a VM using a vsock relay. No network stack required. Works even if the VM has no IP or cloud-init failed.

Terminal

mvm console myvm

Attach to the VM serial console interactively.

Terminal

mvm console myvm --state

Check if the console relay is running (does not attach).

Terminal

mvm console myvm --kill

Kill a stuck console relay.

Press Ctrl+X then D to detach from the console session. This does not shut down the VM.
The console relay runs as a background process. If it crashes, use mvm console --kill then re-attach.
Use --state to check if the relay is running without attaching. Handy for scripting.
Requires the vhost_vsock kernel module. Check with lsmod | grep vsock.

mvm logs

View or stream VM logs. Two types: boot (serial console — kernel boot messages, cloud-init, login prompts) and OS (Firecracker process stderr/stdout).

Terminal

mvm logs myvm --follow

Watch the VM boot in real-time. Best for checking if cloud-init finished.

Terminal

mvm logs myvm --os

Check Firecracker stderr — useful if the VM failed to start.

Terminal

mvm logs myvm

View the full boot log (static, not following).

--follow / -f streams logs in real-time (like tail -f). Press Ctrl+C to stop.
Use --os to show Firecracker process logs instead of serial console output.
Use --lines / -n to limit output to the last N lines.
Log files are in ~/.cache/mvmctl/vms/<vm-sha>/ as firecracker.console.log and firecracker.log.

mvm vm snapshot / load

Saves VM memory and disk state to disk. <code>mvm vm load</code> restores it later. Useful for preserving a long-running VM state before rebooting the host.

Terminal

mvm vm snapshot myvm <mem_file> <state_file>

Snapshot a running VM. Requires memory and state file paths.

Terminal

mvm vm load myvm <mem_file> <state_file>

Restore the VM from memory and state files.

Snapshots can be large — memory + disk. A VM with 2 GiB RAM creates a ~2 GiB memory file.
The VM continues running while being snapshotted. The snapshot is crash-consistent (like pulling the power cord).
Snapshots are stored in ~/.cache/mvmctl/vms/<vm-sha>/snapshots/.

mvm vm ps

List only running VMs (active Firecracker processes). Shows name, status, IP, resources, and image/kernel IDs.

Terminal

mvm vm ps

Show only VMs that are currently running or starting.

mvm vm ls / inspect

Shows detailed VM information: SHA256 hash ID, IP address, network, kernel path, image path, resources, creation time, and current state.

Terminal

mvm vm inspect myvm

Show all details for a VM.

Terminal

mvm vm ls

List all VMs with brief info (name, IP, status).

mvm vm rm / prune

Stops the Firecracker process, removes firewall rules, kills the nocloud-net server, and deletes the VM state directory.

Terminal

mvm vm rm myvm

Remove a VM with confirmation.

Terminal

mvm vm rm myvm -f

Remove without asking (script-friendly).

Terminal

mvm cache prune vm

Remove all stopped VMs at once.

Without --force / -f, the command asks for confirmation. Use --force / -f in scripts.
mvm cache prune vm removes all stopped VMs at once. Asks for confirmation by default.
Removing a VM frees its IP lease, making it available for new VMs.
Stopped VMs (crashed or killed) still show in mvm vm ls until removed with rm or prune.

Resource Management

mvmctl manages five resource types: OS images (root filesystems), kernels (vmlinux binaries), Firecracker/jailer binaries, SSH keys, and persistent data disks (volumes).

mvm image

What images are

Images are root filesystem images (ext4 format) that provide the OS for your microVM. mvmctl can fetch pre-built images from the registry or import local files.

Available images

These image types are defined in mvmctl and can be fetched with mvm image pull <type>:<version> (e.g. mvm image pull ubuntu:24.04) or the longer mvm image pull <type> --version <version> — or use mvm image ls --remote to see all available versions:

  • ubuntu — Ubuntu LTS (tar-rootfs). Versions: 26.04, 24.04, 22.04
  • ubuntu-minimal — Ubuntu Minimal (tar-rootfs). Versions: 26.04, 24.04, 22.04
  • debian — Debian (qcow2). Versions: 13, 12, 11
  • alpine — Alpine Linux (VHD). Versions: 3.x releases
  • archlinux — Arch Linux (qcow2, rolling release — no version needed)
  • firecracker — Firecracker CI Ubuntu (squashfs, from Firecracker S3 bucket)

Fetching images

Terminal

# Fetch an image by type and version
mvm image pull ubuntu --version 24.04

# Shorthand: type:version syntax
mvm image pull ubuntu:24.04

# Alpine Linux
mvm image pull alpine --version 3.21

# Or use shorthand:
mvm image pull alpine:3.21

# Arch Linux (rolling release — no version needed)
mvm image pull archlinux

# Force re-download (overwrites cached copy)
mvm image pull ubuntu:24.04 -f

# List available images (local + remote versions)
mvm image ls
mvm image ls --remote            # Show upstream versions
Shorthand alias: mvm img <command> can be used instead of mvm image <command>. Images are typically 200-800 MB compressed. Cached in ~/.cache/mvmctl/images/. Each VM gets its own copy.

Importing custom images

Have a custom rootfs (e.g., from Packer)? Import it into the cache:

Terminal

mvm image import my-custom-image /path/to/my-custom-image.raw --format raw
mvm image ls                     # Verify it shows up
mvm image default my-custom-image
Syntax: mvm image import NAME SOURCE_PATH. Supports raw images (.raw/.img), qcow2, and tar-rootfs archives (.tar/.tar.gz/.tar.xz/.tgz) natively — no manual conversion needed.

Managing images

Terminal

mvm image ls                          # List all cached images
mvm image inspect <id>                # Show detailed image info
mvm image default <id>             # Set default for new VMs
mvm image rm <id>                     # Remove a cached image (full or short SHA)
mvm image warm <id>                   # Pre-decompress to ready pool for fast VM creation

mvm kernel

What kernels are

Firecracker requires an uncompressed ELF binary (vmlinux) — not the compressed vmlinuz used by traditional bootloaders. mvmctl supports two kernel types.

Firecracker-optimized kernel (recommended)

A pre-built kernel from the Firecracker CI pipeline. Minimally configured for fast boot — no PCI, no ACPI. Downloads in ~30 seconds.

Terminal

mvm kernel pull --type firecracker
# Downloads the latest Firecracker-optimized kernel
This is the default. Use this unless you need custom kernel modules or a specific version. Boots in under 200ms.

Official upstream kernel (custom build)

Downloads the official Linux kernel source (default: 6.19.9) and compiles it with a Firecracker-compatible config. Takes 10-30 minutes.

Terminal

# Build latest upstream kernel
mvm kernel pull --type official

# Using type:version shorthand
mvm kernel pull official:6.19.9

# Build a specific version
mvm kernel pull --type official --version 6.6

# Apply a custom kernel config fragment
mvm kernel pull --type official --config /path/to/my-fragment.config

# Enable kernel features (kvm, nftables)
mvm kernel pull official:6.19.9 --features kvm,nftables

# Specify architecture and parallel build jobs
mvm kernel pull --type official --arch arm64 --jobs 8

# Set as default after fetch
mvm kernel pull --type official --default

# Force clean rebuild (bypass cache)
mvm kernel pull --type official --clean-build
Official builds require build deps: build-essential, flex, bison, libelf-dev, libssl-dev, libncurses-dev, bc, git, curl, pkg-config, dwarves (for pahole). Expect 10-30 min build times. Use --config PATH to apply a custom kernel config fragment, --arch ARCH for architecture (x86_64, arm64), --jobs N for parallel build jobs, and --default to set as default after fetch.

Managing kernels

Terminal

mvm kernel ls                    # List cached kernels
mvm kernel ls --remote           # List remote versions available for download
mvm kernel inspect <id>         # Show detailed kernel info
mvm kernel default <id>        # Set as default for VM creation
mvm kernel import <name> <path>  # Import a custom vmlinux kernel file
mvm kernel rm <id>               # Remove a cached kernel

mvm bin

What binaries are

Firecracker and jailer binaries downloaded from the Firecracker GitHub releases page. You need at least one version downloaded to create VMs.

Managing binaries

Terminal

# Download Firecracker v1.15.0 (includes jailer)
mvm bin pull firecracker --version 1.15.0

# Build Firecracker from source at a git ref
mvm bin pull firecracker --git-ref v1.15.0

# Force re-download even if version already exists
mvm bin pull firecracker --version 1.15.0 --force

# List downloaded versions
mvm bin ls

# List remote versions available for download
mvm bin ls --remote

# Set as active version by ID prefix
mvm bin default abc123

# Remove by version
mvm bin rm --version 1.15.0
mvm bin rm --version 1.15.0 -f   # Force remove even if referenced by VMs

# Remove by ID
mvm bin rm abc123
mvm bin pull downloads both firecracker and jailer together. They must match versions — mixing v1.14 firecracker with v1.15 jailer causes runtime errors.

mvm key

What keys are for

SSH public keys cached by mvmctl for injection into VMs via cloud-init. Without at least one key, you cannot SSH into your VMs (console access still works).

Creating and managing keys

Terminal

# Generate a new ED25519 keypair and set as default (recommended)
mvm key create mykey --default

# Import an existing public key
mvm key add mykey ~/.ssh/id_ed25519.pub
mvm key add mykey ~/.ssh/id_ed25519.pub --force   # Overwrite if key exists

# List all cached keys
mvm key ls

# Show key details
mvm key inspect mykey

# Set default keys for VM creation
mvm key default mykey

# Export a key to a directory (--out is required)
mvm key export mykey --out ~/.ssh/exported

# Remove a key from cache
mvm key rm mykey
mvm key create generates both a public and private key. The private key stays on your machine — mvmctl only stores the public key for cloud-init injection.

How keys work with VMs

When you create a VM with --ssh-key mykey (or use the default key), mvmctl injects the public key into cloud-init user-data. After cloud-init finishes (~30-60s), you can SSH in with mvm ssh myvm.

Network Management

mvmctl uses Linux bridge/TAP networking with NAT (via nftables or iptables). Each named network is a separate bridge with its own subnet.

How networking works

mvmctl uses Linux bridge/TAP networking with NAT (via nftables or iptables). Each named network is a Linux bridge with its own subnet. VMs get TAP interfaces and IPs from a lease pool. Traffic is NATed to the host network.

The default network

The default network is called net and uses 172.27.0.0/24 (gateway: 172.27.0.1). It is created automatically the first time you run mvm host init — no manual network setup needed for basic use.

The default network name is net. The bridge device is named mvm-net (mvm-net), following the convention mvm-<network-name>.

Network commands

Terminal

# Create a named network with a custom subnet
# You will be prompted to select interface(s) for NAT
mvm network create mynet --subnet 10.0.1.0/24

# Create non-interactively (skips NAT gateway prompts)
mvm network create mynet --subnet 10.0.1.0/24 --non-interactive

# Create with explicit NAT gateway interfaces
mvm network create mynet --subnet 10.0.1.0/24 --nat-gateways eth0

# Create without NAT (no internet access for VMs)
mvm network create mynet --subnet 10.0.1.0/24 --no-nat

# Create with explicit gateway IP
mvm network create mynet --subnet 10.0.1.0/24 --ipv4-gateway 10.0.1.1

# Create and set as default network
mvm network create mynet --subnet 10.0.1.0/24 --default

# List all networks
mvm network ls

# Show network details
mvm network inspect mynet

# Set a network as default
mvm network default mynet

# Sync firewall rules between database and host
mvm network sync

# Remove a network (only if no VMs attached)
mvm network rm mynet
Shorthand alias: mvm net <command> can be used instead of mvm network <command>. You cannot remove a network that has VMs attached. Stop and remove the VMs first.

Using networks with VMs

Terminal

# Create a VM on a custom network
mvm network create isolated --subnet 10.0.0.0/24
mvm vm create myvm --image ubuntu:24.04 --network isolated

# Assign a specific IP
mvm vm create myvm --image ubuntu:24.04 --network isolated --ip 10.0.0.50

Custom networks get the subnet you specify. The bridge device is named mvm-<network-name>. Each VM gets a unique MAC address (auto-generated with the 02:FC prefix).

Configuration

Configuration priority

Settings resolve in this order (lower overrides higher):

  1. Built-in defaults from constants.py (compiled into the package, lowest priority)
  2. SQLite database (~/.cache/mvmctl/mvmdb.db) — canonical store for asset defaults
  3. Runtime config file (~/.config/mvmctl/config.json)
  4. MVM_* environment variables
  5. CLI flags (highest priority)

Config file location

Runtime config: ~/.config/mvmctl/config.json (override with MVM_CONFIG_DIR). Asset cache: ~/.cache/mvmctl/ (override with MVM_CACHE_DIR).

Config commands

Terminal

# List all overridable settings and their current values
mvm config list

# Get a specific value
mvm config get defaults.vm vcpu_count

# Set a value (persists to config.json)
mvm config set defaults.vm vcpu_count 4

# Reset a single value to default
mvm config reset defaults.vm vcpu_count

# Reset all overrides globally
mvm config reset --all

Environment variables

Terminal

MVM_CACHE_DIR          Override cache directory               ~/.cache/mvmctl
MVM_CONFIG_DIR         Override config directory               ~/.config/mvmctl
MVM_LOG_LEVEL          Log level: DEBUG, INFO, WARNING, ERROR  WARNING
MVM_FIRECRACKER_BIN    Override Firecracker binary path
MVM_COMPLETE           Set by shell completion system
MVM_ESCALATED          Set by sudo wrapper to indicate             1
                       privilege escalation
MVM_ASSET_MIRROR       Local directory for asset mirroring

Cache management

Terminal

# Initialize cache directories
mvm cache init

# Prune specific resource type
mvm cache prune vm
mvm cache prune network
mvm cache prune image
mvm cache prune kernel
mvm cache prune binary
mvm cache prune misc

# Dry-run prune all (see what would be removed)
mvm cache prune --all --dry-run

# Prune all resources including protected items
mvm cache prune --all

# Prune all without confirmation
mvm cache prune --all --force

# Completely clean all cache (nuclear option)
mvm cache clean
mvm cache clean --dry-run
Always run --dry-run first. Cache pruning is one-way. mvm cache clean removes ALL cached assets AND host networking, but does not touch running VMs unless you use --all.

Dependencies

mvmctl depends on several system binaries. Most are common Linux utilities; this reference covers what each is for and which package provides it.

Core runtime dependencies

These binaries are required for basic mvmctl operations:

BinaryPurposeDebian/UbuntuRHEL/FedoraArch
firecracker + jailerMicroVM VMM + security isolationmvm bin pullmvm bin pullmvm bin pull
ipBridge/TAP managementiproute2iproute2iproute2
iptablesNAT and firewall rulesiptablesiptablesiptables
iptables-savePersisting iptables rulesiptablesiptablesiptables
nft / nftablesNAT and firewall rules (default backend)nftablesnftablesnftables
sysctlIP forwardingprocpsprocps-ngprocps-ng
modprobeKVM module loadingkmodkmodkmod
lsmodKVM module statuskmodkmodkmod
groupaddmvm group creationpasswdshadowshadow
usermodUser group membershippasswdshadowshadow
visudoSudoers validationsudosudosudo
sudoPrivileged commandssudosudosudo
groupdelRemoving the mvm group on resetpasswdshadowshadow
dumpe2fsFilesystem inspectione2fsprogse2fsprogse2fsprogs

Image & cloud-init dependencies

BinaryPurposeDebian/UbuntuRHEL/FedoraArch
qemu-imgImage conversion/resizeqemu-utilsqemu-imgqemu-img
sfdiskPartition table manipulationutil-linuxutil-linuxutil-linux
partedPartition readingpartedpartedparted
blkidRoot partition/UUID detectionutil-linuxutil-linuxutil-linux
mount/umountImage mountingutil-linuxutil-linuxutil-linux
truncateSparse file creationcoreutilscoreutilscoreutils
mkfs.ext4Rootfs formattinge2fsprogse2fsprogse2fsprogs
unsquashfsSquashFS extractionsquashfs-toolssquashfs-toolssquashfs-tools
tarTarball extractiontartartar
zstdImage compression/decompressionzstdzstdzstd
cloud-localdsCloud-init seed ISOcloud-image-utilscloud-utilscloud-utils
ssh-keygenSSH key generationopenssh-clientopensshopenssh
sshVM connectionopenssh-clientopensshopenssh

libguestfs (optional — for cloud-init direct injection)

Required only if you use --cloud-init-mode inject and the primary loop-mount provisioner is unavailable. The guestfs Python module is not on PyPI — install via your package manager.

Terminal

# Debian/Ubuntu
sudo apt-get install libguestfs0 libguestfs-tools supermin python3-libguestfs

# RHEL/CentOS/Fedora
sudo dnf install libguestfs libguestfs-tools supermin

# Arch
sudo pacman -S libguestfs supermin

# Verify
python3 -c 'import guestfs; print("OK")'

Building kernels from source

Building official kernels from source requires additional build dependencies (make, gcc, flex, bison, libelf, openssl, ncurses, bc, pahole, git, curl, pkg-config). See the full custom-kernel guide for details.

Provisioning backend comparison

mvmctl supports two root filesystem provisioning backends. The loop-mount backend is the default (~200ms per VM). libguestfs is an opt-in alternative (~2600ms per VM) enabled via mvm init. See the runtime documentation for technical details.

AspectLoop-Mount (default)libguestfs (opt-in)
Speed~200ms per VM~2600-3000ms per VM
DependenciesCompiled binary (extracted by mvm init)System packages (python3-libguestfs, supermin, qemu)
SetupAutomatic (mvm init)Opt-in via mvm init or mvm config set

Command dependency mapping

This table maps specific mvm commands to the external binaries they invoke:

Command GroupCommand(s)Required Binaries
mvm hostinitsudo, groupadd, usermod, visudo, sysctl, ip, iptables, iptables-save, lsmod, modprobe
lsip, iptables
cleanip, iptables
resetsudo, groupdel, sysctl, ip, iptables
mvm networkcreateip, iptables
ls, inspect, rm, sync, defaultip, iptables
mvm imageimportqemu-img, sfdisk, parted, blkid, mount, umount, tar, truncate, mkfs.ext4, unsquashfs
warmqemu-img
mvm kernelpull --type official --clean-buildmake, gcc, ld, flex, bison, bc, pahole, git, curl, pkg-config
mvm keycreatessh-keygen
mvm vmcreatefirecracker, jailer, ip, iptables, losetup, blkid, blockdev, mount, umount, e2fsck, resize2fs, tune2fs, chroot (+ btrfs for btrfs images)
start, stop, reboot, rmfirecracker, ip, iptables

Host system requirements

  • Kernel modules: kvm, kvm_intel or kvm_amd, tun, bridge, vhost_vsock
  • Hardware virtualization: VT-x (Intel) or AMD-V must be enabled in BIOS/UEFI
  • Permissions: The user must be in the mvm group (created by mvm host init)

Cloud-Init

Cloud-init configures your VM on first boot: users, SSH keys, networking, startup scripts. mvmctl handles this automatically.

What is cloud-init?

Cloud-init configures your VM on first boot: sets up users, injects SSH keys, configures networking, runs startup scripts. mvmctl handles this automatically.

How mvmctl handles cloud-init

Defaults to off if not specified. Set via --cloud-init-mode on mvm vm create. The available modes are:

Cloud-init modes

  • inject — injects cloud-init files directly into the rootfs via loop-mount provisioner (with libguestfs as fallback). Fastest and most reliable.
  • net — starts a temporary HTTP server (nocloud-net). The VM fetches config during boot via ds=nocloud-net;s=http://GATEWAY_IP:PORT/. No libguestfs needed.
  • iso — attaches a CD-ROM ISO with cloud-init files. Compatible with all images. Slower (requires cloud-localds).
  • off (default) — disables cloud-init entirely. VM boots with no user setup.

How nocloud-net (net mode) works

  • A temporary HTTP server starts on an available port (8000-9000 range)
  • Firewall rules allow only the specific VM to reach its server
  • The VM boots with the nocloud-net kernel command line datasource
  • Cloud-init fetches meta-data, user-data, and network-config via HTTP
  • The HTTP server auto-cleans up when the VM is removed

Security model

  • Each VM gets its own HTTP server on a unique port
  • Source-based firewall rules — only the VM's IP can reach its server
  • Servers bind to the bridge gateway IP, not 0.0.0.0
  • Rules are tagged with # mvm-nocloud:<vm_name>:<port>

Troubleshooting

Common issues, what causes them, and how to fix them:

Permission denied: /dev/kvm

Terminal

# First check if /dev/kvm exists:
ls -l /dev/kvm

# Case 1 — does not exist (KVM modules not loaded):
sudo modprobe kvm
sudo modprobe kvm_intel    # or kvm_amd on AMD

# Case 2 — exists but not writable (group membership):
sudo usermod -aG kvm $USER
# Then log out and back in

If /dev/kvm does not exist after modprobe, install KVM modules (e.g. linux-modules-extra-* on Ubuntu). Group membership takes effect on next login.

Bridge mvm-net not found

Terminal

# The bridge is created automatically. Ensure host init ran:
sudo mvm host init

Re-running sudo mvm host init is safe (idempotent). The default bridge is named mvm-net.

Image not found

Terminal

mvm image pull ubuntu --version 24.04
mvm image ls   # Verify it appears

Image IDs are case-sensitive. Use mvm image ls to see available images.

Kernel not found

Terminal

mvm kernel pull --type firecracker
mvm kernel ls           # Verify it is cached
mvm kernel ls --remote  # List available remote versions

Default fetch downloads a Firecracker-optimized kernel (~30s). Official builds take 10-30 min.

Firecracker binary not found

Terminal

mvm bin pull firecracker --version v1.15
mvm bin default <id>

Always run mvm bin default <id> after fetching. The default version (e.g. v1.15) matches the installed Firecracker release — you can also pull other versions with mvm bin pull firecracker --version <version>.

VM won't boot / SSH times out

Terminal

# Watch boot progress:
mvm logs myvm --follow

# If nothing at all, check Firecracker process log:
mvm logs myvm --os

Wait at least 60 seconds before assuming the VM is stuck. If the boot log shows nothing, the kernel may be incompatible or the image corrupt.

NoCloud-net server failed to start

Terminal

# Port range (8000-9000) may be exhausted
sudo ss -tlnp | grep -E ':(8[0-9]{3}|9[0-9]{3})'
# Kill orphaned servers
pkill -f mvm-nocloud-server

Each VM uses one port in 8000-9000. If many VMs were not cleaned up, orphaned servers may still be running.

Mixed iptables backends (Docker conflict)

Terminal

# Symptom: VM has IP, ping works, but TCP times out
# Detection:
iptables --version
sudo iptables-legacy -L -n -v

# Fix: clear orphaned legacy rules
sudo iptables-legacy -F

# Then re-run: sudo mvm host init

Docker may switch to iptables-legacy while mvmctl uses iptables-nft. Rules end up in different places. Reboot clears both backends.

Network creation fails with permission denied

Terminal

# Check mvm group membership
groups | grep mvm

# If not in group:
sudo usermod -aG mvm $USER
# Then log out and back in

The mvm group also requires a new login session. Use newgrp mvm to avoid logging out.

Console relay not working

Terminal

# Check relay status
mvm console myvm --state

# Kill and re-attach
mvm console myvm --kill
mvm console myvm

The console relay uses vsock. Ensure vhost_vsock kernel module is loaded: lsmod | grep vsock.

Cache corruption or stale state

Terminal

# Preview what would be removed
mvm cache prune --all --dry-run

# Remove stale entries from a specific type
mvm cache prune vm

# Full reset (removes ALL VMs — careful!)
mvm cache prune --all

Cache corruption usually shows as metadata pointing to deleted files, or phantom VMs. mvm cache prune reconciles metadata with actual files.

Volume attach fails — volume is already attached

Terminal

# Check volume status
mvm volume inspect my-data

# Detach from current VM first
mvm vm detach-volume <vm-name> my-data

# Force remove (use with caution)
mvm volume rm my-data -f

A volume can only be attached to one VM at a time. Detach it first or create a new volume. Use --force / -f on volume rm to skip the attached check.

Debug mode

Enable verbose logging to see what mvmctl is doing under the hood:

Terminal

# Run a single command with debug output:
MVM_LOG_LEVEL=DEBUG mvm vm create myvm --image ubuntu:24.04

# Or use the --debug flag:
mvm --debug vm create myvm --image ubuntu:24.04
Use MVM_LOG_LEVEL=DEBUG prefix or --debug flag for any command. Debug output is verbose.

Getting help

Still stuck? Open an issue on GitHub with:

  • The exact command you ran
  • Full error output (run with MVM_LOG_LEVEL=DEBUG)
  • Your OS and mvm --version