This project runs a Firecracker microVM whose root filesystem is served from an AgentFS overlay over NFS.
This repository contains the build and launch scripts only. Generated artifacts such as rootfs/, linux-amazon/, .agentfs/, vmlinux, and temporary vm_config.*.json files are intentionally excluded from version control.
- Guest rootfs: Ubuntu 24.04
noble, built withdebootstrap - Guest kernel: Amazon Linux microVM kernel tag
microvm-kernel-6.1.167-27.319.amzn2023 - Firecracker target:
v1.15.1 - AgentFS target:
v0.6.4 - Pi:
@mariozechner/pi-coding-agent@latestfrom npm
build-kernel.shclones the Amazon Linux kernel repo and buildsvmlinux.build-rootfs.shbootstraps an Ubuntu rootfs and installs developer tooling into it.firecracker.shcreates or reuses an AgentFS overlay in.agentfs/<agent-id>.db.firecracker.shexports that overlay over NFS using the hostagentfsbinary.- Firecracker boots the VM with
root=/dev/nfs, so the guest rootfs is the AgentFS-backed overlay. - The launcher sets up a TAP device plus outbound NAT so the guest can reach the internet.
The practical effect is:
- the guest starts from a reusable Ubuntu base image
- all guest filesystem changes are persisted into the AgentFS SQLite DB
- you can inspect changes later with
agentfs diff <agent-id>
You need these on the host:
- Ubuntu or another Linux host with
sudo - KVM / Firecracker support
agentfsinstalled on the host and available onPATH- package install permissions for
apt,debootstrap, TAP setup, andiptables
build-rootfs.sh, build-kernel.sh, and firecracker.sh all require sudo.
The launcher expects:
- host uplink interface detectable from
ip route show default iptablesavailable for NAT
Host-side:
- Firecracker process
- AgentFS NFS server
- TAP device and NAT rules
- AgentFS overlay DBs in
.agentfs/
Guest-side:
- Ubuntu userspace
- developer tools
/workspacesshd- outbound access to GitHub, npm, and Ubuntu mirrors through host NAT
- hostname:
agentvm - user:
dev - password:
devby default, configurable withVM_USER_PASSWORD - sudo: passwordless
- working directory after login:
/workspace - default VM size:
4vCPU,8192MiB RAM - default network:
- host TAP device:
fc-tap0 - host TAP IP:
172.16.0.1 - guest IP:
172.16.0.2 - subnet:
172.16.0.0/24
- host TAP device:
- default AgentFS NFS port:
11111
Base development tools:
git,git-lfs,ghripgrep,fd,bat,jq,tmux,tree,htop,stracevim,neovim,nanocurl,wget,rsync,zip,unzipclang,lld,llvm,cmake,ninja-build,gdb,pkg-configsqlite3,shellcheck
Rust toolchain:
rustupcargorustcclippyrustfmtrust-analyzer
Python toolchain:
python3python3-devpippipxvenvuvpytestmypyblackruffipython
Node / agent tooling:
- Node.js from NodeSource
20.xby default npmpi- guest
agentfs
pi is wrapped to extract a prebuilt package archive into /tmp/pi-package-<uid> on first launch, which avoids walking the NFS-backed package tree at runtime.
Relevant development libraries installed in the guest:
libssl-devlibsqlite3-devlibffi-devlibclang-devlibxml2-devlibxmlsec1-devlibyaml-devlibbz2-devliblzma-devlibreadline-devlibgdbm-devlibncurses5-devlibncursesw5-dev
Single command for first-time setup and launch:
cd /home/mitko/dev/firecracker-agentfs
chmod +x run.sh build-kernel.sh build-rootfs.sh firecracker.sh
./run.shrun.sh:
- builds the kernel if it is missing
- builds the rootfs if it is missing
- starts Firecracker with AgentFS
After kernel config changes, force a kernel rebuild:
./run.sh --build-kernelAfter rootfs changes like SSH setup, force a rootfs rebuild too:
RESET_AGENTFS=1 ./run.sh --build-all my-agentIf you want the explicit manual steps instead:
cd /home/mitko/dev/firecracker-agentfs
chmod +x build-kernel.sh build-rootfs.sh firecracker.sh
./build-kernel.sh
./build-rootfs.shWhat those scripts do:
build-kernel.shinstalls host build deps withapt, clones the Amazon Linux kernel, enables Firecracker/NFS/dev-friendly kernel options, and buildsvmlinux- if
linux-amazon/already exists and is clean,build-kernel.shwill switch it to the requestedKERNEL_TAGautomatically build-rootfs.shinstalls host-side bootstrap deps, recreates./rootfs, bootstraps Ubuntunoble, installs guest packages, Rust, Python tools, Pi, and guest AgentFS, then writes/initand guest profile files
./run.shor directly:
./firecracker.shUse a custom AgentFS overlay id:
./run.sh my-agentor:
./firecracker.sh my-agentIf the base rootfs changed and you want to recreate the overlay for an existing id:
RESET_AGENTFS=1 ./run.sh my-agentor:
RESET_AGENTFS=1 ./firecracker.sh my-agentStop the VM with Ctrl+C.
Serial console:
./run.shIf the guest boots successfully, you should land directly in an interactive shell as dev in the same terminal.
SSH from the host:
ssh dev@172.16.0.2Default password:
dev
To use a different password:
VM_USER_PASSWORD='something-better' ./build-rootfs.sh
RESET_AGENTFS=1 ./run.sh --build-rootfs my-agentIf host SSH public keys exist in ~/.ssh/*.pub at rootfs build time, they are copied into the guest user's authorized_keys.
Guest 127.0.0.1 is the VM itself, not the host. To reach host services that are bound only to host localhost, connect from the VM to the host TAP IP instead:
172.16.0.1:8000-8010
By default, firecracker.sh forwards guest TCP connections to 172.16.0.1:8000-8010 into host 127.0.0.1:8000-8010.
Examples from inside the VM:
curl http://172.16.0.1:8000
curl http://172.16.0.1:8010To change or disable that forwarding:
HOST_LOOPBACK_PORTS=3000,5173 ./run.sh
HOST_LOOPBACK_PORTS= ./run.sh- Base image:
./rootfs - Overlay DB:
.agentfs/<agent-id>.db - Base stamp:
.agentfs/<agent-id>.base-stamp
The launcher hashes rootfs/etc/agentvm-release and refuses to silently reuse an overlay against a changed base rootfs. If the base image changed, either:
- use a new agent id, or
- run with
RESET_AGENTFS=1
vm_config.jsonis not checked in anymore; it is generated as a temporary file at launch time.- If the host
firecrackerbinary is missing or on the wrong version,firecracker.shdownloadsv1.15.1into./bin/. - The host
agentfsbinary is not auto-installed by the launcher. Install it yourself first. - The launcher warns if the host
agentfsversion does not match the expected target version. - The guest rootfs is served from AgentFS over NFSv3.
firecracker.shkills stale AgentFS NFS exports on the configured bind/port before starting a new one.- Guest boot logs are visible by default. To suppress them, use
GUEST_KERNEL_QUIET=1. - The guest shell is started under
setsid --cttyso it can claim the Firecracker serial console as its controlling TTY.
Build-time:
./run.sh --build-all
./run.sh --build-rootfs
RESET_AGENTFS=1 ./run.sh --build-rootfs my-agent
NODE_MAJOR=20 ./build-rootfs.sh
RUST_TOOLCHAIN=stable ./build-rootfs.sh
VM_USER=dev VM_USER_PASSWORD=dev VM_HOSTNAME=agentvm ./build-rootfs.sh
KERNEL_TAG=microvm-kernel-6.1.167-27.319.amzn2023 ./build-kernel.shRun-time:
VM_VCPUS=4 VM_MEM_MIB=4096 ./firecracker.sh
HOST_IFACE=wlp194s0 ./firecracker.sh
TAP_DEV=fc-tap1 HOST_TAP_IP=172.16.1.1 VM_IP=172.16.1.2 VM_SUBNET=172.16.1.0/24 ./firecracker.sh
NFS_PORT=11112 ./firecracker.sh
GUEST_KERNEL_QUIET=1 ./firecracker.shAvailable environment knobs used by the scripts:
build-rootfs.shROOTFS_DIRROOTFS_RELEASEROOTFS_MIRRORROOTFS_ARCHVM_USERVM_USER_PASSWORDVM_HOSTNAMENODE_MAJORPI_PACKAGERUST_TOOLCHAINEXTRA_APT_PACKAGESEXTRA_NPM_PACKAGESHOST_SSH_DIR
run.shBUILD_KERNEL_MODEBUILD_ROOTFS_MODE
build-kernel.shKERNEL_DIRKERNEL_TAG
firecracker.shROOTFS_DIRKERNEL_PATHLOCAL_BIN_DIRFIRECRACKER_VERSIONAGENTFS_VERSIONFIRECRACKER_BINAGENTFS_BINTAP_DEVHOST_TAP_IPVM_IPVM_SUBNETHOST_IFACENFS_PORTHOST_LOOPBACK_PORTSVM_HOSTNAMEVM_VCPUSVM_MEM_MIBFIRECRACKER_LOG_LEVELRESET_AGENTFSGUEST_KERNEL_LOGLEVELGUEST_KERNEL_QUIET
agentfs diff <agent-id>You can also inspect the AgentFS database directly from .agentfs/ if needed.