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/kvmand membership in thekvmgroup - Python 3.13+ for pip/pipx/source installs
- Root access once for host setup (
mvm initorsudo mvm host init) nftablesfor 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 kmodTerminal
sudo pacman -S --needed iproute2 iptables nftables cloud-utils qemu-img e2fsprogs kmod--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 --helpIsolated Python app install. Keeps mvmctl separate from system Python.
Terminal
pipx install mvmctl
mvm --helpSystem or virtualenv install.
Terminal
pip install mvmctl
mvm --helpFor local development or contributing.
Terminal
git clone https://github.com/AlanD20/mvmctl
cd mvmctl
uv sync
uv run mvm --helpmvm --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 initnewgrp 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 initmvm 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_amdkernel modules (networking modulestunandbridgeare loaded as needed) - Enables
net.ipv4.ip_forwardfor NAT networking - Creates the
mvmsystem group and adds your user to it - Writes a sudoers drop-in to
/etc/sudoers.d/mvmso mvmctl can run privileged commands (ip, iptables, sysctl, modprobe) without password prompts - Sets up the
mvm-netbridge 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 groupmvm 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 -fmvm logs myvm --follow. mvm key create NAME --default or pass --ssh-key explicitly when creating a VM. ~/.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.04Defaults: 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 50GUseful 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.50The 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 ubuntuThe --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 256Alpine 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.yamlCustom 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-dataThe --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).
mvm vm create starts the VM immediately. net) uses 172.27.0.0/24. Leases are reused when VMs are removed. --disk-size flag resizes via qemu-img resize. It only grows the image — shrinking requires manual intervention. --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 myvmSSH as the default user (root by default unless --user was specified).
Terminal
mvm ssh myvm --user adminSSH as a specific user.
ssh -i commands. But you do need a key set up beforehand. 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 myvmAttach to the VM serial console interactively.
Terminal
mvm console myvm --stateCheck if the console relay is running (does not attach).
Terminal
mvm console myvm --killKill a stuck console relay.
Ctrl+X then D to detach from the console session. This does not shut down the VM. mvm console --kill then re-attach. --state to check if the relay is running without attaching. Handy for scripting. 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 --followWatch the VM boot in real-time. Best for checking if cloud-init finished.
Terminal
mvm logs myvm --osCheck Firecracker stderr — useful if the VM failed to start.
Terminal
mvm logs myvmView the full boot log (static, not following).
--follow / -f streams logs in real-time (like tail -f). Press Ctrl+C to stop. --os to show Firecracker process logs instead of serial console output. --lines / -n to limit output to the last N lines. ~/.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.
~/.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 psShow 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 myvmShow all details for a VM.
Terminal
mvm vm lsList 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 myvmRemove a VM with confirmation.
Terminal
mvm vm rm myvm -fRemove without asking (script-friendly).
Terminal
mvm cache prune vmRemove all stopped VMs at once.
--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. 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.04ubuntu-minimal— Ubuntu Minimal (tar-rootfs). Versions: 26.04, 24.04, 22.04debian— Debian (qcow2). Versions: 13, 12, 11alpine— Alpine Linux (VHD). Versions: 3.x releasesarchlinux— 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 versionsmvm 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-imagemvm 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 creationmvm 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 kernelOfficial 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-buildbuild-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 kernelmvm 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 abc123mvm 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 mykeymvm 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.
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 mynetmvm 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.50Custom 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):
- Built-in defaults from
constants.py(compiled into the package, lowest priority) - SQLite database (
~/.cache/mvmctl/mvmdb.db) — canonical store for asset defaults - Runtime config file (
~/.config/mvmctl/config.json) MVM_*environment variables- 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 --allEnvironment 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 mirroringCache 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--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:
| Binary | Purpose | Debian/Ubuntu | RHEL/Fedora | Arch |
|---|---|---|---|---|
firecracker + jailer | MicroVM VMM + security isolation | mvm bin pull | mvm bin pull | mvm bin pull |
ip | Bridge/TAP management | iproute2 | iproute2 | iproute2 |
iptables | NAT and firewall rules | iptables | iptables | iptables |
iptables-save | Persisting iptables rules | iptables | iptables | iptables |
nft / nftables | NAT and firewall rules (default backend) | nftables | nftables | nftables |
sysctl | IP forwarding | procps | procps-ng | procps-ng |
modprobe | KVM module loading | kmod | kmod | kmod |
lsmod | KVM module status | kmod | kmod | kmod |
groupadd | mvm group creation | passwd | shadow | shadow |
usermod | User group membership | passwd | shadow | shadow |
visudo | Sudoers validation | sudo | sudo | sudo |
sudo | Privileged commands | sudo | sudo | sudo |
groupdel | Removing the mvm group on reset | passwd | shadow | shadow |
dumpe2fs | Filesystem inspection | e2fsprogs | e2fsprogs | e2fsprogs |
Image & cloud-init dependencies
| Binary | Purpose | Debian/Ubuntu | RHEL/Fedora | Arch |
|---|---|---|---|---|
qemu-img | Image conversion/resize | qemu-utils | qemu-img | qemu-img |
sfdisk | Partition table manipulation | util-linux | util-linux | util-linux |
parted | Partition reading | parted | parted | parted |
blkid | Root partition/UUID detection | util-linux | util-linux | util-linux |
mount/umount | Image mounting | util-linux | util-linux | util-linux |
truncate | Sparse file creation | coreutils | coreutils | coreutils |
mkfs.ext4 | Rootfs formatting | e2fsprogs | e2fsprogs | e2fsprogs |
unsquashfs | SquashFS extraction | squashfs-tools | squashfs-tools | squashfs-tools |
tar | Tarball extraction | tar | tar | tar |
zstd | Image compression/decompression | zstd | zstd | zstd |
cloud-localds | Cloud-init seed ISO | cloud-image-utils | cloud-utils | cloud-utils |
ssh-keygen | SSH key generation | openssh-client | openssh | openssh |
ssh | VM connection | openssh-client | openssh | openssh |
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.
| Aspect | Loop-Mount (default) | libguestfs (opt-in) |
|---|---|---|
Speed | ~200ms per VM | ~2600-3000ms per VM |
Dependencies | Compiled binary (extracted by mvm init) | System packages (python3-libguestfs, supermin, qemu) |
Setup | Automatic (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 Group | Command(s) | Required Binaries |
|---|---|---|
mvm host | init | sudo, groupadd, usermod, visudo, sysctl, ip, iptables, iptables-save, lsmod, modprobe |
| ls | ip, iptables |
| clean | ip, iptables |
| reset | sudo, groupdel, sysctl, ip, iptables |
mvm network | create | ip, iptables |
| ls, inspect, rm, sync, default | ip, iptables |
mvm image | import | qemu-img, sfdisk, parted, blkid, mount, umount, tar, truncate, mkfs.ext4, unsquashfs |
| warm | qemu-img |
mvm kernel | pull --type official --clean-build | make, gcc, ld, flex, bison, bc, pahole, git, curl, pkg-config |
mvm key | create | ssh-keygen |
mvm vm | create | firecracker, jailer, ip, iptables, losetup, blkid, blockdev, mount, umount, e2fsck, resize2fs, tune2fs, chroot (+ btrfs for btrfs images) |
| start, stop, reboot, rm | firecracker, ip, iptables |
Host system requirements
- Kernel modules:
kvm,kvm_intelorkvm_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
mvmgroup (created bymvm 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 viads=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 (requirescloud-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, andnetwork-configvia 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 inIf /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 initRe-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 appearsImage 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 versionsDefault 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 --osWait 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-serverEach 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 initDocker 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 inThe 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 myvmThe 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 --allCache 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 -fA 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.04MVM_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