Skip to main content

Husker

An open-source microVM manager built on Firecracker (Linux) and Apple Virtualization.framework (macOS).

  • Boot lightweight VMs in seconds (about 1s from a warm pool)
  • Execute commands, transfer files, open interactive shells
  • Stream serial console logs
  • Port forwarding (nftables NAT on Linux, a userspace TCP proxy on macOS)
  • REST API + CLI
  • Prepared development images, detached agent sessions, and private previews
  • Synchronous Python client for VM lifecycle, commands, files, and sessions
  • Durable hard expirations for externally orchestrated ephemeral VMs
  • Cloud-init style userdata scripts

Status

Pre-1.0. The core feature set works and has test coverage, but:

  • The HTTP API, CLI flags, config schema, and on-disk state layout may change without a deprecation period.
  • The Linux/Firecracker backend is more mature than the macOS/Apple VZ backend.
  • It has not been run at scale or under production workloads.
  • Security features (token auth, rate limiting, encrypted secrets) exist but have had limited review. Don't expose the daemon to an untrusted network.

Useful for experimentation, local development, and CI. Not recommended for production.

Where Husker is useful

Husker works best as an execution plane beside your long-lived infrastructure:

  • disposable sandboxes for risky agent or dependency-heavy commands;
  • memory-isolated build offload with explicit artifact return;
  • single-use CI runners replaced from a clean image after every job;
  • scheduled scripts that need secrets and network access but no permanent host;
  • trusted integration VMs that can reach private registries and test services;
  • warm pools for repeated short tasks where cold-start latency dominates.

Keep databases, ingress, monitoring, and other durable services on the platform already responsible for their state. Separate untrusted internet-only jobs from trusted jobs that need private-network access instead of weakening one shared boundary.

Quick Start

For the prepared-image, agent, and private-preview workflow, see Development computers.

Install

macOS (Homebrew):

brew install rvben/tap/husker

Linux & macOS (installer script):

curl -sSfL https://raw.githubusercontent.com/rvben/husker/main/install.sh | sh

Cross-platform (PyPI):

pip install husker

Pinning a version: curl -sSfL https://raw.githubusercontent.com/rvben/husker/main/install.sh | HUSKER_VERSION=v0.1.2 sh or pip install husker==0.1.2.

First boot

# Fetch the default kernel + rootfs for this host
husker images pull

# Start the daemon
husker daemon &

# Confirm it came up (checks the daemon, images, and backend)
husker doctor

# Boot a VM
husker run --name hello --cpus 2 --memory 512

# Interact
husker exec hello -- uname -a
husker shell hello
husker cp local.txt hello:/tmp/local.txt
husker logs hello -f

# Clean up
husker destroy hello

In text mode, husker exec streams stdout and stderr while the command runs. --output json intentionally returns one complete result document after exit, which keeps automation atomic and machine-readable. VMs using an older guest agent remain compatible but buffer output until their image is refreshed.

On Linux, husker run needs firecracker on PATH. If it's missing, husker prompts to download a pinned release into the data directory. For non-interactive use (CI, scripts), set HUSKER_AUTO_INSTALL_FIRECRACKER=1 to skip the prompt.

husker images pull fetches the latest image set from the images-* GitHub Releases and verifies each asset against the published SHA256SUMS. If no image release is published yet for this arch, the command will fail - use the BYO path below in the meantime.

BYO kernel / rootfs

If you want to use your own images, pass --kernel and the rootfs path:

husker run /path/to/rootfs.ext4 --kernel /path/to/vmlinux

Docker inside a VM

The default Husker kernel includes the namespaces, cgroup BPF, OverlayFS, bridge/veth, nftables, iptables compatibility, and seccomp support required by Docker, containerd, and runc. Allocate enough disk and memory for the daemon and its image store; the 128 MiB VM default is intended for lightweight jobs, not a container daemon.

husker run alpine:latest --name docker-host --cpus 2 --memory 1024 --disk-size 4G
husker exec docker-host -- apk add --no-cache docker
husker shell docker-host

# Inside the VM:
dockerd >/var/log/dockerd.log 2>&1 &
docker run --rm alpine:latest echo container-ok

Running an OCI image directly with husker job <image> remains lighter when a nested container daemon is unnecessary. See Docker and container runtimes for usage, kernel compatibility, and troubleshooting details.

Hot Pools

A pool is a pre-warmed, suspended template VM that husker forks fresh, isolated VMs from in about a second, instead of a 6-8s cold boot. Each fork inherits the template's already-booted state (kernel up, guest agent running, whatever you installed), so checkouts are fast and start from a known-good baseline. Hot pools build on Firecracker's snapshot/restore (Linux).

# Create a pool: boots a template VM once, warms it, then suspends it.
husker pool create web --vcpus 2 --memory 512

# Fork a fresh, isolated VM out of the pool (~1s).
husker pool checkout web --name task-42
husker exec task-42 -- ./run-tests.sh
husker destroy task-42

# Inspect and tear down.
husker pool list
husker pool get web
husker pool delete web

A single pool can be checked out many times concurrently: each fork gets its own IP, vsock CID, and copy-on-write rootfs, fully isolated from its siblings and from the template (the template stays suspended and is never mutated).

run and job can draw straight from a pool with --pool, the fast path for sandboxing untrusted or agentic work. The image and boot flags come from the pool's template, so pass only --name (plus job's --sync-cwd/--out) and your command:

# One-shot: fork from the pool, run the command, then destroy the VM.
husker job --pool web -- make test

# Long-lived: fork from the pool instead of cold-booting.
husker run --pool web --name preview

Configuration

Copy config.example.toml to one of the discovery paths:

  1. ~/.config/husker/config.toml (user)
  2. /etc/husker/config.toml (system)

Or pass --config /path/to/config.toml explicitly. See config.example.toml for all available fields.

Platform Support

Platform Backend Networking Status
Linux x86_64 Firecracker TAP + nftables NAT, port forwarding Usable
macOS ARM64 Apple Virtualization.framework Shared NAT (VZ-managed), port forwarding (userspace proxy) Experimental
Linux x86_64 QEMU/KVM TAP + nftables NAT, port forwarding Experimental

Intel macOS and Windows are not supported (Windows: use WSL2). Linux also supports aarch64 (agent-less build - see below).

Feature support by backend

Feature Firecracker (Linux) QEMU (Linux) Apple VZ (macOS)
Direct-kernel boot ✓ ✓ ✓
Cloud images (--cloud-image) — ¹ ✓ (UEFI/OVMF) ✓ (EFI)
macOS guests (--macos) - - ✓ ⁴
exec / shell / file copy ✓ ✓ ✓
One-shot jobs (husker job) ✓ ✓ ✓
Self-healing services ✓ ✓ ✓ ²
Persistent volumes (--volume) ✓ ✓ ✓ ²
Host bind-mounts (--mount) — ✓ (virtiofs) —
Memory balloon (--balloon) ✓ ✓ ✓
Bridged LAN (--net bridged) — ✓ ³ —
Offline network (--net none) ✓ ✓ ✓ (no NIC attached)
Per-VM egress allowlist (API network: filtered) ✓ ✓ —
Snapshots ✓ — —
Fork / pool checkout ✓ — —
Idle suspend / resume ✓ — —

Notes:

  1. Cloud-image boot needs UEFI; Firecracker does direct-kernel boot only, so use --vmm qemu on Linux for cloud images.
  2. On macOS, --volume and services are not yet supported together with --cloud-image (both work with the default rootfs).
  3. Bridged networking requires a cloud-image VM (so --vmm qemu) plus the lan_bridge config option, and is Linux-only.
  4. Apple Silicon only. See macOS guests below.

Only the two primary targets (Linux x86_64 and macOS ARM64) ship with the embedded guest agent. The Linux ARM64 and Intel-macOS builds are agent-less: husker run boots, but exec/shell/cp and cloud-image VMs need the agent, so they will report the agent as unreachable. husker doctor flags a missing embedded agent. Use a primary-target build for full functionality.

QEMU/KVM backend (Linux)

Besides Firecracker microVMs, husker can run full QEMU/KVM VMs on Linux. Select it with vmm = "qemu" in the config file or HUSKER_VMM=qemu. Requires /dev/kvm, /dev/vhost-vsock (load the vhost_vsock kernel module), and qemu-system-x86_64 on PATH (override with HUSKER_QEMU_BIN).

Current scope is direct-kernel boot (same kernel + rootfs model as the Firecracker backend), with the guest agent reachable over vsock. Cloud-image boot via UEFI/OVMF is also supported - see the Cloud Images section below.

The QEMU backend also enables host bind-mounts via virtiofs: share a host directory into the guest in real time with --mount <host>:<guest>[:ro]. See docs/host-mounts.md.

Guest kernel requirement: the QEMU backend uses the q35 machine, which puts the root disk, NIC, and vsock device on the PCI bus, so the guest kernel must have CONFIG_VIRTIO_PCI (and an initramfs if virtio_blk is a module). The default husker images satisfy this. Firecracker's own kernels are built for virtio-MMIO only and will panic under QEMU with Cannot open root device "vda". The husker default images and most distro kernels work as-is.

Cloud Images

husker can boot stock cloud images (Ubuntu, Debian, etc.) on both platforms:

  • Linux: QEMU/OVMF (UEFI boot). Requires ovmf_code and ovmf_vars in config.
  • macOS (Apple Silicon): Apple Virtualization.framework with built-in EFI.

macOS prerequisites

brew install qemu        # qemu-img is used for qcow2-to-raw conversion
brew install e2fsprogs   # debugfs/resize2fs: refresh the guest agent in rootfs clones, grow rootfs images

Homebrew installs e2fsprogs keg-only; husker finds it in the keg without any PATH changes, and husker doctor reports which tools it found.

Example (macOS)

# Download a cloud image (ARM64 for Apple Silicon)
curl -LO https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-arm64.img

husker run --name ubuntu \
  --cloud-image ubuntu-24.04-server-cloudimg-arm64.img \
  --ssh-key ~/.ssh/id_ed25519.pub

Networking uses VZ shared NAT; the guest gets a DHCP address in the 192.168.64.x range. The guest IP appears in husker info ubuntu once the agent reports it (typically within 20-30 seconds of first boot). Connect with husker shell ubuntu or via SSH once the IP is known.

Not yet supported on macOS with cloud images: --volume, --balloon, and services (husker service). Host bind-mounts (--mount) and bridged networking (--net bridged) are Linux-only with any image.

macOS guests

On Apple Silicon, husker runs macOS itself as a guest through Virtualization.framework: install an image from Apple's latest restore image (or a local IPSW), provision the guest agent into it once, then boot VMs from it (up to two at a time, Apple's limit), each with its own cloned disk and machine identifier.

husker macos install sonoma                                   # downloads the latest IPSW and installs it
sudo husker macos provision ~/.local/share/husker/macos/sonoma # installs the guest agent (needs root)
husker run --macos sonoma --name mac1
husker exec mac1 -- sw_vers

See docs/macos-guests.md for requirements, options and limitations.

Alternatives

husker is one of several ways to run microVMs. Rough positioning:

Tool Backend Focus Notes
husker Firecracker (Linux) + Apple VZ (macOS) Single-host VM manager with a REST API and CLI SQLite-backed state, port forwarding, guest agent over vsock.
Ignite Firecracker Docker-image-style workflow on Firecracker Archived by Weaveworks; Linux only.
firecracker-containerd Firecracker containerd runtime backed by microVMs Kubernetes-friendly; Linux only.
krunvm libkrun OCI-image microVMs on macOS No daemon; ephemeral per-command VMs.
Lima QEMU (+ VZ on macOS) Full Linux VMs as a dev environment Heavier than Firecracker; broader guest support.

Pick husker if you want Firecracker on Linux with a matching Apple VZ path on macOS, driven by a single CLI + daemon.

Architecture

CLI (husker) ──> REST API (husker-api) ──> Core (husker-core)
                                           ├── VMM (husker-vmm)      Firecracker / Apple VZ
                                           ├── State (husker-state)  SQLite persistence
                                           ├── Net (husker-net)      TAP devices, IP allocation
                                           └── Storage (husker-storage) Rootfs cloning
                                       Guest Agent (husker-agent) ←── Proto (husker-agent-proto)

Host-guest communication uses vsock (port 52). Messages are length-prefixed JSON with base64-encoded binary payloads.

Once the daemon is running, the REST API is browsable at http://127.0.0.1:7777/docs (Swagger UI), with the raw OpenAPI schema at /api-docs/openapi.json.

External orchestrators can attach a hard lifetime when creating a VM by adding expires_after_secs and an optional informational owner to POST /v1/vms. The deadline is stored atomically with the VM record, is not extended by guest activity, appears as expires_at/owner in VM responses, and is reaped by the daemon even if the orchestrator disappears. See Werkt integration for the intended execution-plane boundary.

Linux API clients can request a default-deny egress boundary with network: "filtered" and explicit hostname/protocol/port entries. Husker resolves and pins those entries before boot, then restores the concrete policy after daemon restarts. See Per-VM egress policies.

Security

The daemon defaults to loopback-only. Don't bind it on a public interface without a bearer token and a terminating reverse proxy.

Troubleshooting

husker run can't find firecracker (Linux) On a TTY, husker prompts to download a pinned release. For scripted/CI use, set HUSKER_AUTO_INSTALL_FIRECRACKER=1 to skip the prompt, or install Firecracker yourself from the releases page.

husker run reports kvm_init: permission denied (Linux) Add your user to the kvm group: sudo usermod -aG kvm $USER and re-login.

husker run fails on macOS with a virtualization entitlement error The binary needs the com.apple.security.virtualization entitlement. pip, brew, and the installer script all ship a codesigned binary. If you built from source, run make install — it ad-hoc signs via husker.entitlements.

macOS: VM boots but exits immediately Apple VZ needs an initramfs to mount the rootfs. If you're using custom images, make sure --initrd points at a matching initramfs (see guest/build-initramfs.sh).

husker daemon binds but the CLI can't connect The CLI defaults to http://127.0.0.1:7777. If the daemon listens elsewhere, pass --api-url http://host:port (and --api-token if auth is enabled).

Rootfs edits don't take effect on macOS Use make update-rootfs to inject changes via debugfs (works in LXC and macOS). Loop-mounting doesn't work on macOS.

Development

Requires Rust 1.90+ and cargo-nextest.

make build          # Debug build
make build-release  # Release build (LTO, stripped)
make build-agent    # Static musl agent for guest VMs
make test           # Full test suite
make test-unit      # Unit tests only
make lint           # fmt-check + clippy
make check          # Type check
make install        # Install (auto-detects macOS, signs binary)

Running a Development VM

make run-daemon                     # Start daemon
make build-agent-aarch64            # Build ARM64 agent (macOS guests)
make update-rootfs                  # Inject agent into rootfs image

Systemd

A systemd unit file is provided at contrib/husker.service. Keep its KillMode=mixed: with systemd's default control-group mode every guest is signalled together with the daemon on stop, so guests die before the daemon can drain them, and with process a guest that outlives the drain keeps running after the unit has stopped. scripts/deploy-linux.sh refuses to stop a unit with any other mode.

Contributing

Issues and pull requests welcome. See CONTRIBUTING.md for the dev workflow and commit conventions.

License

See LICENSE.

Releasing

Vership owns versioning, changelog generation, release commits, and tags. See the release runbook for the verified workflow and recovery policy.

Session submission pilot

POST /v1/vms/{name}/session-submissions accepts the usual exec fields plus a non-secret idempotency_key. It requires a matching protocol v7 guest agent and returns the same session for identical submissions in the same VM generation. Changed resolved command/environment/timeout values and removed sessions are conflicts. Policy or injected-secret changes can therefore invalidate a replay; use the original effective specification, or inspect the existing session.

The guest durably publishes a v1 specification hash and status before spawning. An accepted command interrupted before spawn is reported interrupted rather than executed again. Its environment and arguments are not stored in the receipt. Removed submission IDs retain bounded receipts until VM destruction. The 1024 receipt budget blocks new replay acceptances, while cleanup and ordinary sessions remain available. This endpoint is intended for disposable VMs: do not upgrade or downgrade the agent in place while retaining a replay ledger. Rebuild the image and replace the VM instead. The older /sessions endpoint retains its existing start/remove semantics.

Metadata

Release files for husker 0.4.55

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for husker 0.4.55
File Size Uploaded Provenance Actions
husker-0.4.55.tar.gz 1.1 MB Without provenance Details for husker-0.4.55.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for husker 0.4.55
File Actions
husker-0.4.55-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details for husker-0.4.55-py3-none-manylinux_2_28_x86_64.whl
husker-0.4.55-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details for husker-0.4.55-py3-none-manylinux_2_28_aarch64.whl
husker-0.4.55-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for husker-0.4.55-py3-none-macosx_11_0_arm64.whl
husker-0.4.55-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details for husker-0.4.55-py3-none-macosx_10_12_x86_64.whl

Total release size: 42.0 MB

Release files / husker-0.4.55.tar.gz

Download URL husker-0.4.55.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
77cc1cf69437f80d76333bd6a54fa4f1165803a65f1b105e0ac5f393ccb80c56
BLAKE2b-256 checksum
How to use checksums
a45e12d37cbf3c88f07533fef949b438bb83ee1a480dd6c71c5f8a16168ccf44
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / husker-0.4.55-py3-none-manylinux_2_28_x86_64.whl

Download URL husker-0.4.55-py3-none-manylinux_2_28_x86_64.whl
Size 11.0 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
93614477fd8c96729b4ff400c7a240102659a2c9925ef4ca898346fdb979f13e
BLAKE2b-256 checksum
How to use checksums
041c88bdb86dcbc93ca8511be0e019f77dbd910b629dde353d0483bc55df6be3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / husker-0.4.55-py3-none-manylinux_2_28_aarch64.whl

Download URL husker-0.4.55-py3-none-manylinux_2_28_aarch64.whl
Size 9.6 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
7c02385bc3b2eb6800be82943407bbc18523e75465ba73823da80d1d56587f93
BLAKE2b-256 checksum
How to use checksums
6fd7fa8bd2a848b4940b4555d5fa5c171a9384815c97d9d20de7814e99ada65e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / husker-0.4.55-py3-none-macosx_11_0_arm64.whl

Download URL husker-0.4.55-py3-none-macosx_11_0_arm64.whl
Size 10.1 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
bf87e2222111f44439ea86ce50771c54650bc71743cf57fb85f5ee416e94d9a3
BLAKE2b-256 checksum
How to use checksums
18bea8a39f134755f5fa5c5f571a225702dc474c8170b66e0713ca758552a900
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / husker-0.4.55-py3-none-macosx_10_12_x86_64.whl

Download URL husker-0.4.55-py3-none-macosx_10_12_x86_64.whl
Size 10.2 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
e0f0784c7d1d6de3833b4a681960449d6700c6b31ab23ea64fb53ee08647f1c5
BLAKE2b-256 checksum
How to use checksums
92125dc1aeb559246e35110348012a339b7be04dc65a9ab109e40e3127c56ffb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Security for husker 0.4.55

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.4.55 This release

5 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page