MicroVMs
    KVM Required

    Deploy Firecracker on a VPS

    AWS's Lambda/Fargate VMM. Sub-second microVM boots, ~5 MiB overhead per instance, jailer-wrapped isolation.

    At a Glance

    ProjectFirecracker (AWS)
    LicenseApache 2.0
    RequiresKVM (/dev/kvm) on host
    OSUbuntu 22.04 / 24.04, kernel 5.10+
    Use casesFaaS, hardened container isolation, per-tenant VMs
    1

    Verify KVM Availability

    Prerequisite checks
    lsmod | grep kvm
    ls -l /dev/kvm
    grep -E 'vmx|svm' /proc/cpuinfo | head -1

    If /dev/kvm does not exist, your VPS does not expose nested virtualization and Firecracker will not work. There is no workaround — move to a host that supports KVM.

    Install basics + grant KVM access
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y curl ca-certificates iproute2 iptables net-tools bridge-utils acl jq
    
    sudo usermod -aG kvm $USER
    sudo setfacl -m u:${USER}:rw /dev/kvm
    [ -r /dev/kvm ] && [ -w /dev/kvm ] && echo "OK" || echo "FAIL"
    2

    Install Firecracker + Jailer

    Download latest release
    cd /tmp
    ARCH=$(uname -m)
    FC_VERSION=$(curl -s https://api.github.com/repos/firecracker-microvm/firecracker/releases/latest | jq -r .tag_name)
    curl -fL "https://github.com/firecracker-microvm/firecracker/releases/download/${FC_VERSION}/firecracker-${FC_VERSION}-${ARCH}.tgz" -o firecracker.tgz
    tar -xzf firecracker.tgz
    
    sudo install -m 0755 "release-${FC_VERSION}-${ARCH}/firecracker-${FC_VERSION}-${ARCH}" /usr/local/bin/firecracker
    sudo install -m 0755 "release-${FC_VERSION}-${ARCH}/jailer-${FC_VERSION}-${ARCH}" /usr/local/bin/jailer
    
    firecracker --version && jailer --version
    3

    Kernel + Rootfs Image

    Pull sample images
    mkdir -p /var/lib/firecracker/images && cd /var/lib/firecracker/images
    sudo chown $USER:$USER /var/lib/firecracker/images
    
    ARCH=$(uname -m)
    curl -L "https://s3.amazonaws.com/spec.ccfc.min/firecracker-ci/v1.10/${ARCH}/vmlinux-5.10.225" -o vmlinux.bin
    curl -L "https://s3.amazonaws.com/spec.ccfc.min/firecracker-ci/v1.10/${ARCH}/ubuntu-24.04.squashfs" -o ubuntu-24.04.squashfs
    Convert squashfs to writable ext4
    mkdir -p /tmp/sqfs-mnt /tmp/ext4-mnt
    sudo mount -o loop,ro ubuntu-24.04.squashfs /tmp/sqfs-mnt
    
    dd if=/dev/zero of=ubuntu-24.04.ext4 bs=1M count=2048
    mkfs.ext4 ubuntu-24.04.ext4
    
    sudo mount -o loop ubuntu-24.04.ext4 /tmp/ext4-mnt
    sudo rsync -a /tmp/sqfs-mnt/ /tmp/ext4-mnt/
    sudo umount /tmp/ext4-mnt /tmp/sqfs-mnt
    4

    Host Bridge + Tap Networking

    systemd-networkd bridge
    sudo tee /etc/systemd/network/10-fc-br0.netdev > /dev/null <<'EOF'
    [NetDev]
    Name=fc-br0
    Kind=bridge
    EOF
    
    sudo tee /etc/systemd/network/20-fc-br0.network > /dev/null <<'EOF'
    [Match]
    Name=fc-br0
    
    [Network]
    Address=172.30.0.1/24
    IPMasquerade=ipv4
    ConfigureWithoutCarrier=true
    EOF
    
    sudo systemctl enable --now systemd-networkd
    sudo systemctl restart systemd-networkd
    Forwarding + masquerade
    echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-firecracker.conf
    sudo sysctl --system
    
    PRIMARY_IFACE=$(ip route show default | awk '/default/ {print $5}' | head -1)
    sudo iptables -t nat -A POSTROUTING -s 172.30.0.0/24 ! -o fc-br0 -j MASQUERADE
    sudo iptables -A FORWARD -i fc-br0 -j ACCEPT
    sudo iptables -A FORWARD -o fc-br0 -j ACCEPT
    
    sudo apt install -y iptables-persistent
    sudo netfilter-persistent save
    Per-microVM tap
    sudo ip tuntap add tap0 mode tap
    sudo ip link set tap0 master fc-br0
    sudo ip link set tap0 up
    5

    Boot Your First MicroVM

    vm-config.json
    {
      "boot-source": {
        "kernel_image_path": "/var/lib/firecracker/images/vmlinux.bin",
        "boot_args": "console=ttyS0 reboot=k panic=1 pci=off ip=172.30.0.10::172.30.0.1:255.255.255.0::eth0:off"
      },
      "drives": [
        {
          "drive_id": "rootfs",
          "path_on_host": "/var/lib/firecracker/images/ubuntu-24.04.ext4",
          "is_root_device": true,
          "is_read_only": false
        }
      ],
      "network-interfaces": [
        {
          "iface_id": "eth0",
          "guest_mac": "AA:FC:00:00:00:01",
          "host_dev_name": "tap0"
        }
      ],
      "machine-config": {
        "vcpu_count": 1,
        "mem_size_mib": 256,
        "smt": false
      }
    }
    Start it
    mkdir -p /var/lib/firecracker/vms/test1
    cp vm-config.json /var/lib/firecracker/vms/test1/
    firecracker --config-file /var/lib/firecracker/vms/test1/vm-config.json
    # Default creds for the sample image: root / root
    # Inside guest: ip a; ping 8.8.8.8
    6

    Run Under the Jailer (Production)

    For production, never run firecracker directly. The jailer sets up chroot, drops capabilities, applies cgroups, switches UID/GID, and applies seccomp filters before exec.

    Create unprivileged user + jail
    sudo useradd --system --create-home --home-dir /var/lib/firecracker --shell /usr/sbin/nologin firecracker
    
    VM_ID="vm-prod-1"
    JAIL_BASE="/srv/jailer"
    JAIL_ROOT="${JAIL_BASE}/firecracker/${VM_ID}/root"
    
    sudo mkdir -p "${JAIL_ROOT}"
    sudo cp /var/lib/firecracker/images/vmlinux.bin "${JAIL_ROOT}/vmlinux.bin"
    sudo cp /var/lib/firecracker/images/ubuntu-24.04.ext4 "${JAIL_ROOT}/rootfs.ext4"
    
    FC_UID=$(id -u firecracker); FC_GID=$(id -g firecracker)
    sudo chown -R ${FC_UID}:${FC_GID} "${JAIL_BASE}/firecracker/${VM_ID}"
    
    sudo ip tuntap add tap-prod-1 mode tap user firecracker
    sudo ip link set tap-prod-1 master fc-br0
    sudo ip link set tap-prod-1 up
    Launch under jailer
    sudo jailer \
      --id "${VM_ID}" \
      --exec-file /usr/local/bin/firecracker \
      --uid ${FC_UID} --gid ${FC_GID} \
      --chroot-base-dir "${JAIL_BASE}" \
      --new-pid-ns \
      --resource-limit no-file=2048 \
      --resource-limit fsize=10737418240 \
      -- --api-sock /run/firecracker.socket
    7

    Production Host Hardening

    Disable swap + KSM (data isolation)
    sudo swapoff -a
    sudo sed -i '/swap/d' /etc/fstab
    echo 0 | sudo tee /sys/kernel/mm/ksm/run
    echo "@reboot root echo 0 > /sys/kernel/mm/ksm/run" | sudo tee /etc/cron.d/disable-ksm

    Apply CPU microcode updates, run a recent kernel (5.10/6.1 are tested), and confirm speculative-execution mitigations with lscpu | grep -i vulnerab. For production guests, drop the serial console and pass 8250.nr_uarts=0.

    8

    Snapshots, Caddy Ingress, Updates

    Snapshot a running microVM
    sudo curl --unix-socket "${API_SOCKET}" -X PUT 'http://localhost/snapshot/create' \
      -H 'Content-Type: application/json' \
      -d '{
        "snapshot_type": "Full",
        "snapshot_path": "/var/backups/snapshot.bin",
        "mem_file_path": "/var/backups/memory.bin"
      }'
    Caddyfile fronting a guest
    app.example.com {
        reverse_proxy 172.30.0.10:8080 {
            header_up X-Real-IP {remote_host}
            header_up X-Forwarded-For {remote_host}
        }
        encode zstd gzip
        header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    }

    Updates are a binary swap of firecracker and jailer. Running microVMs are unaffected; new launches pick up the new binary. Read the changelog before upgrading — API field names occasionally shift.