hardpass is a small Rust CLI for managing local Ubuntu cloud-image VMs with QEMU.
It exists for people who want a simpler, more predictable local VM workflow than Multipass:
- macOS and Linux hosts
- Ubuntu guest images only
- host-native guest architecture by default, with optional cross-architecture TCG emulation
- QEMU user networking
- stable per-VM SSH port forwarding
doctorchecks for required local tools and firmware.image prefetchdownloads and verifies a cloud image into the local cache.createcreates a named VM.startboots a named VM and waits for SSH.stopgracefully stops a named VM.deletestops and removes a named VM.listshows known VMs.info [--json]prints VM details.sshopens an interactive SSH session.execruns a remote command over SSH.
From crates.io:
cargo install hardpass-vmThat installs the hp executable.
From the GitHub repository:
cargo install --git https://github.com/peterdelevoryas/hardpassFrom a local checkout:
cargo install --path .That installs hp into Cargo's bin directory so the examples below can be run directly.
hp doctor
hp image prefetch
hp create dev
hp start dev
hp list
hp info dev
hp ssh dev
hp exec dev -- uname -a
hp stop dev
hp delete devcreate defaults to Ubuntu 24.04 on the host-native guest architecture with 2 vCPUs, 8192 MiB RAM, and a 16 GiB disk. You can override VM size, acceleration, guest arch, and forwarding when needed:
hp create test \
--release 24.04 \
--cpus 4 \
--memory-mib 16384 \
--disk-gib 100 \
--forward 8080:8080
hp start testUse --accel tcg when you want slower emulated guests, including cross-architecture experiments such as --arch amd64 on an arm64 host.
If you want to warm the image cache before the first VM boot:
hp image prefetch
hp image prefetch --release 24.04 --arch amd64Use info --json when another tool needs machine-readable state:
hp info dev --jsonThe JSON payload includes ssh.alias, so other tools can discover the SSH alias directly.
Hardpass stores state under ~/.hardpass by default. Set HARDPASS_HOME if you want a different root.
When using the default ~/.hardpass root, Hardpass automatically:
- adds
Include ~/.hardpass/ssh/configto~/.ssh/config - rewrites
~/.hardpass/ssh/configto match the current VM aliases
Each VM name becomes an SSH alias with the stored loopback port and identity file:
ssh devWith the default ~/.hardpass root, hp create and hp delete keep the alias file up to date automatically.
qemu-imgqemu-system-x86_64orqemu-system-aarch64sshssh-keygen- Linux hosts need
/dev/kvmfor--accel autoor--accel kvm;--accel tcgis also supported but slower - AArch64 hosts also need discoverable UEFI firmware for QEMU
Run hp doctor to confirm the local environment before creating a VM.
- SSH connections disable host key checking and known-host persistence for loopback convenience.
- The default cloud-init config creates an
ubuntuuser with passwordless sudo. - Guest networking uses QEMU user networking, not bridged networking.
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo testThe real-QEMU integration smoke test is opt-in:
HARDPASS_REAL_QEMU_TEST=1 cargo test --test library_api_smoke -- --ignoredThe heavier GitHub Actions e2e test is also opt-in locally on macOS and Linux hosts:
HARDPASS_REAL_QEMU_TEST=1 cargo test --test e2e_vm_stress -- --ignored --nocaptureBoth real-QEMU tests use the current HOME and the normal Hardpass state at ~/.hardpass, so they share the default image cache and exercise the same SSH-config behavior a user would get in CI. While they run, you can inspect them with ordinary cargo run -- list, cargo run -- info <name>, and cargo run -- ssh <name>.
In GitHub Actions, the e2e workflow requires /dev/kvm and intentionally fails instead of falling back to TCG.
Set HARDPASS_E2E_PROFILE=stress to run the 2-VM profile locally.