This episode covers the jailer — Firecracker's last line of defense. You'll wrap the microVM in namespaces, cgroups, seccomp, a read-only rootfs, and a non-root user, understand the --id, --chroot-base-dir, and --exec-file flags, and apply defense-in-depth if the hypervisor is breached.

So far we've been running Firecracker as an ordinary process — as root, with no restrictions. In the real world, that's never enough. Episode 7 introduces the jailer: a security wrapper that cages the Firecracker process so that if the microVM is breached, an attacker only finds empty walls.
Why is this episode important? Because all of Firecracker's security claims — multi-tenant isolation, untrusted workloads — stand on the jailer. KVM protects the host from the guest, but who protects the host from the VMM itself? The answer: the jailer, using deep Linux isolation mechanisms — namespaces, cgroups, seccomp, a read-only rootfs, and privilege drop.
Firecracker's threat model is layered:
The jailer is a response that assumes the VMM can be breached. With that assumption, it ensures that penetrating the VMM doesn't mean penetrating the host. This is the same pattern as container sandboxes: don't trust that bugs won't happen — design so bugs aren't dangerous.
When you run jailer --exec-file ./firecracker, the jailer does several things in sequence before executing Firecracker:
The final result: the Firecracker process lives in a small world it can't leave — exactly the jailer's purpose.
The basic pattern for running a microVM through the jailer:
sudo jailer \
--id 1001 \
--exec-file /usr/local/bin/firecracker \
--uid 123 \
--gid 100 \
--chroot-base-dir /srv/jailer \
--netns /var/run/netns/fcns \
--node 0Understanding the important flags:
--id <uid> — the microVM's unique identity. The jailer uses it to create the chroot-base-dir/<id> directory as the process's home. Every VM must have a different --id.--chroot-base-dir — the directory where the jailer builds the new root (/srv/jailer/<id>/). Kernel files, rootfs, and the API socket must be copied into it so the process can see them.--exec-file — the binary to execute after jailing (Firecracker).--uid / --gid — the non-root UID/GID that runs the process. Firecracker doesn't need root; it only needs access to /dev/kvm and its own files.--netns — moves the process into a specific network namespace, providing per-VM network isolation.--node — the NUMA node to pin vCPUs to.Once the jailer runs, the API socket lives at /srv/jailer/<id>/run/firecracker.socket — not in /tmp anymore. All subsequent interaction goes through the socket inside the chroot:
curl --unix-socket /srv/jailer/1001/run/firecracker.socket http://localhost/Important
Inside the jail, kernel and rootfs paths must be relative to the chroot. After the jailer, Firecracker sees the filesystem as /srv/jailer/1001/ acting as root /. So kernel_image_path in the API must be written as /vmlinux.bin (the file copied to /srv/jailer/1001/vmlinux.bin), not the host's absolute path.
The jailer changes the process's filesystem perspective. Everything Firecracker needs must be inside the chroot:
sudo mkdir -p /srv/jailer/1001
sudo cp /home/user/fc-demo/vmlinux.bin /srv/jailer/1001/vmlinux.bin
sudo cp /home/user/fc-demo/rootfs.ext4 /srv/jailer/1001/rootfs.ext4Then all paths in the API payload use chroot-relative paths:
{
"kernel_image_path": "/vmlinux.bin",
"boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
}The pattern: the host cps files into the chroot, and the API references paths inside it. This is also a security benefit — processes inside the chroot can't see files outside, so other VMs' kernels and rootfs are unreachable.
Firecracker's seccomp filter builds a whitelist of syscalls the process is allowed to make. Dangerous syscalls like mount, ptrace, kexec, or userfaultfd are rejected with an error — even if an attacker manages to execute arbitrary code inside the process.
The jailer loads a seccomp profile matching the host architecture. For special needs the profile can be customized, but the principle is always: the narrower the whitelist, the smaller the attacker's reach. Extra syscalls are only added when the workload genuinely requires them — for example, for a new device or feature.
Some habits that should become reflex:
--id: never share a chroot between VMs.memory.max and cpu.max on a dedicated cgroup, so one VM leaking memory doesn't kill its neighbors (details in episode 10).--uid/--gid is a prerequisite, not optional.400 Bad Request or file not found.--id: two VMs using the same --id → the jailer refuses or the chroots clash./tmp: after the jailer, the socket is no longer in /tmp; it's at chroot-base-dir/<id>/run/firecracker.socket.--netns, the TAP must exist in that namespace — create it after entering the namespace or with ip netns exec./dev/kvm access: make sure the non-root user has read/write permission on /dev/kvm (e.g. via the kvm group).The key takeaways:
--id, --chroot-base-dir, --exec-file, --uid/--gid, --netns are the core flags.In the next episode 8 we'll prepare the right provisions for every microVM: MicroVM Images — Build & Kernel Optimization — building a minimal rootfs with Alpine/musl, configuring the kernel to load only the drivers you need, choosing the right boot params, and getting to know tooling such as firectl, firecracker-containerd, NixOS microvm.nix, and mkosi.