Skip to content

Building from source

Updated

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
  1. Build the console first. The web UI is embedded into the binary by rust-embed (src/webui.rs reads web/dist/), so a missing build output fails the Rust compile with E0599 rather than producing an agent with no UI.

    Terminal window
    cd web && pnpm install --frozen-lockfile && pnpm build && cd ..
  2. Build the agent.

    Terminal window
    cargo build --release # -> target/release/virtainer

    The release profile uses lto = "thin" across the workspace.

Terminal window
sudo target/release/virtainer serve

The 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.

Open the console. A host with no state forces a setup wizard, network then storage then host identity, which creates the first admin account.

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.

The frontend does not need Rust during development. Vite serves it and proxies /api to a live agent:

Terminal window
cd web
VA_DEV_API=https://<address-of-a-running-agent> pnpm dev

VA_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:

Terminal window
cd web && pnpm build && cd .. && touch src/webui.rs && cargo build --release

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:

Terminal window
rm -rf target/*/incremental # pure cache, rebuilt on demand
cargo clean -p virtainer # this crate only; dependencies are kept

The second is cheap: rebuilding just this crate takes tens of seconds because the third-party dependencies survive.