Building from source
Updated
Prerequisites
Section titled “Prerequisites”| Requirement | Why it is needed |
|---|---|
Rust 1.95.0 |
Pinned in rust-toolchain.toml, together with rustfmt and clippy. CI installs the same pin, so a lint rule cannot pass locally and fail remotely |
| Node.js 22 and pnpm | The console is a React app built before the Rust crate |
cargo-deny |
tools/preflight.sh checks dependency advisories and licenses |
x86_64-unknown-linux-musl target |
vmkit-init, the AppVM guest’s first process, is built statically for it |
jq, tar, gzip, sha256sum |
Used by the build and release scripts |
-
Build the console first. The web UI is embedded into the binary by
rust-embed(src/webui.rsreadsweb/dist/), so a missing build output fails the Rust compile withE0599rather than producing an agent with no UI.Terminal window cd web && pnpm install --frozen-lockfile && pnpm build && cd .. -
Build the agent.
Terminal window cargo build --release # -> target/release/virtainerThe release profile uses
lto = "thin"across the workspace.
sudo target/release/virtainer serveThe agent listens on 0.0.0.0:80 by default. It is intended to be the only web
service on the host, so the console URL needs no port. Binding below 1024 requires
privilege, and the shipped systemd unit runs as root.
VIRTAINER_LISTEN_PORT=8080 target/release/virtainer serveUseful for reading the console and exercising the API on a development machine. It will not boot real VMs: that needs the host baseline below.
Open the console. A host with no state forces a setup wizard, network then storage then host identity, which creates the first admin account.
What a machine needs to boot real VMs
Section titled “What a machine needs to boot real VMs”The agent drives Cloud Hypervisor, qemu-storage-daemon for disk backends, and an OVMF
firmware build for guest boot. On a development machine that means a Fedora host with
those three present; on a shipped host they are inside the bootc image, which is
described in The bootc host image.
Without them the agent still serves the console and the API, and VM operations fail. That distinction matters when reading a failure: an agent that answers HTTP is not a host that can start a machine.
Working on the console
Section titled “Working on the console”The frontend does not need Rust during development. Vite serves it and proxies /api
to a live agent:
cd webVA_DEV_API=https://<address-of-a-running-agent> pnpm devVA_DEV_API can also go in web/.env.local, which is gitignored.
To see a frontend change inside the compiled binary, the embed needs to be invalidated:
cd web && pnpm build && cd .. && touch src/webui.rs && cargo build --releaseKeeping the build directory honest
Section titled “Keeping the build directory honest”target/ grows without bound because cargo never reclaims stale incremental
artifacts or old copies of the same binary. The project has measured 241 GB in this
tree, of which 116 GB was target/debug/incremental and 1458 files in deps/ were
obsolete builds of the same crate. Two commands returned it to 33 GB:
rm -rf target/*/incremental # pure cache, rebuilt on demandcargo clean -p virtainer # this crate only; dependencies are keptThe second is cheap: rebuilding just this crate takes tens of seconds because the third-party dependencies survive.