Serverless Firecracker — Lambda-like autoscaling for any Docker image
Point fcctl serve at any Docker image and get an autoscaling fleet of Firecracker microVMs with sub-20ms warm starts, per-slot snapshot caching, and a real-time dashboard.
$ fcctl serve my-api --port 8080 --max 20
╭───────────────────────────────────────────────────────────────────╮
│ 🔥 fcctl gateway http://localhost:8080 image=my-api max=20 │
╰───────────────────────────────────────────────────────────────────╯
Instances: 3 idle 2 busy 5 paused 1 booting
Requests: 2 active / 1,847 total
Starts: 4 cold (1.2s) 38 warm (9ms) 156 snapshot (473ms)
Dashboard: http://localhost:8080/dashboard
One command. Zero config. Your Docker app runs inside hardware-isolated microVMs that boot in milliseconds.
- Features
- Architecture
- Quick Start
- CLI Reference
- Gateway & Autoscaling
- Snapshot Engine
- Dashboard
- Benchmarks
- Stress Testing
- Configuration
- Roadmap
- 🚀 Lambda-like Autoscaling — Pool scales from min to max based on request load, scales down on idle
- ⚡ Sub-20ms Warm Starts — Paused VMs resume from memory in ~9ms
- 📸 Per-Slot Snapshot Caching — First boot creates a snapshot; subsequent boots restore in ~300ms instead of cold-booting in ~1.5s
- 🐳 Docker Native — Any Docker image becomes a Firecracker microVM rootfs automatically
- 🔒 Hardware Isolation — Each request runs in its own KVM-backed VM, not a container
- 📊 Real-time Dashboard — React SPA with live instance states, request metrics, and event stream via SSE
- 🌐 Reverse Proxy — HTTP gateway with request queuing, health checks, and connection draining
- 🔄 Lifecycle Management —
run,pause,resume,stop,deletefor individual VMs - 📈 Built-in Benchmarks — Cold / warm / snapshot boot timing with percentile breakdowns
- 🧪 Stress Test Suite — 5-phase autoscaling exerciser (ramp → sustain → burst → cooldown → second burst)
┌────────────────────────────────┐
HTTP Request ──────────► fcctl gateway │
│ │
│ ┌──────────────────────────┐ │
│ │ Pool Manager │ │
│ │ │ │
│ │ acquire() logic: │ │
│ │ 1. idle VM? → use it │ │
│ │ 2. resume paused (9ms) │ │
│ │ 3. snapshot restore │ │
│ │ 4. cold boot │ │
│ │ 5. queue (at capacity) │ │
│ └──────────┬───────────────┘ │
│ │ │
└─────────────┼───────────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ microVM 1 │ │ microVM 2 │ │ microVM N │
│ 172.16.0.6 │ │ 172.16.0.10 │ │ 172.16.0.xx │
│ tap_fc1 │ │ tap_fc2 │ │ tap_fcN │
│ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │
│ │ Your App │ │ │ │ Your App │ │ │ │ Your App │ │
│ │ :3000 │ │ │ │ :3000 │ │ │ │ :3000 │ │
│ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │
└─────────────┘ └─────────────┘ └─────────────┘
KVM/VT-x KVM/VT-x KVM/VT-x
Each VM runs on its own TAP interface with NAT routing. The gateway proxies requests and adds response headers (X-Instance-Id, X-Latency-Ms) for observability.
- Linux with KVM support (
/dev/kvmmust exist) - Docker (for building rootfs from images)
- Node.js 20+
- Root access (Firecracker requires
/dev/kvmand TAP networking)
git clone https://github.com/paradisecy/fcctl.git
cd fcctl
npm install
npm run build
npm link # installs 'fcctl' globally# Boot an Express app in a Firecracker microVM
fcctl run my-docker-image --name my-app --mem 256
# Check it's running
fcctl list
# Get details
fcctl info my-app
# Pause (freezes state, near-zero resource usage)
fcctl pause my-app
# Resume (~9ms)
fcctl resume my-app
# Clean up
fcctl stop my-app
fcctl delete my-app# Start autoscaling gateway — any Docker image works
fcctl serve my-api --port 8080 --min 2 --max 20 --idle-timeout 30
# Requests are automatically routed to VMs
curl http://localhost:8080/
curl http://localhost:8080/api/users
# Watch the dashboard
open http://localhost:8080/dashboard| Command | Alias | Description |
|---|---|---|
fcctl run <image> |
Create and boot a VM from a Docker image | |
fcctl list |
ls |
List all VMs |
fcctl info <id|name> |
Show VM details | |
fcctl pause <id|name> |
sleep |
Pause a running VM |
fcctl resume <id|name> |
wake |
Resume a paused VM |
fcctl stop <id|name> |
Stop a running VM | |
fcctl delete <id|name> |
rm |
Delete a VM (--force to kill first) |
fcctl serve <image> |
Start serverless gateway | |
fcctl help |
-h |
Show help |
| Flag | Default | Description |
|---|---|---|
--name |
auto-generated | Custom VM name |
--cpus |
1 |
vCPU count |
--mem |
256 |
Memory in MiB |
--disk-size |
1024 |
Rootfs disk size in MiB |
| Flag | Default | Description |
|---|---|---|
--port |
8080 |
Gateway listen port |
--app-port |
3000 |
Guest application port |
--mem |
128 |
Memory per VM in MiB |
--concurrency |
1 |
Max concurrent requests per VM |
--min |
1 |
Minimum pool size (always warm) |
--max |
10 |
Maximum pool size |
--idle-timeout |
30 |
Seconds before idle VM is paused |
--scale-down |
300 |
Seconds before paused VM is destroyed |
The gateway implements a 5-tier request acquisition strategy:
- Idle VM — Route immediately (0ms overhead)
- Busy VM with capacity — If
concurrency > 1, reuse busy VMs - Resume paused VM — Warm start from memory (~9ms)
- Snapshot restore — Boot from cached snapshot (~300-500ms)
- Cold boot — Full boot from rootfs (~1.5s)
- Queue — Wait for capacity if at
--max
cold boot ──► idle ──► busy ──► idle ──► paused ──► destroyed
▲ │ │ │
│ ▼ │ ▼
└── request ──────┘ scale-down
(if > min)
Every proxied response includes headers:
X-Instance-Id: a1b2c3d4
X-Instance-Ip: 172.16.0.6
X-Latency-Ms: 12
| Endpoint | Method | Description |
|---|---|---|
/api/status |
GET | Pool stats, instances, config |
/api/instances |
GET | Detailed instance list |
/api/events |
GET | SSE stream (real-time updates) |
/dashboard |
GET | Web dashboard UI |
/* |
ANY | Proxied to VM pool |
The snapshot system eliminates cold boots after the first run on each slot.
- First boot on slot N: Full cold boot → app becomes healthy → VM is paused → memory + state saved as snapshot
- Subsequent boots on slot N: Copy rootfs to stable slot path → load snapshot → resume VM → app is immediately ready
Firecracker snapshots bake the TAP interface name and rootfs path into the VM state. fcctl uses stable per-slot paths so snapshots are reusable:
~/.firecracker-orchestrator/
├── slot-rootfs/
│ ├── slot-1.ext4 # Stable path for slot 1
│ ├── slot-2.ext4 # Stable path for slot 2
│ └── ...
├── snapshots/
│ ├── fc-node-hello-1024mb-3000-slot1/
│ │ ├── snapshot.bin # VM state (17KB)
│ │ ├── mem.bin # Memory (sparse: 85MB of 256MB)
│ │ └── rootfs.ext4 # Disk at snapshot time
│ └── ...
└── rootfs-cache/
└── fc-node-hello-1024mb.ext4 # Base rootfs (built once from Docker)
- Parallel copies: Rootfs and mem.bin are copied concurrently while Firecracker process starts
- Sparse memory:
mem.binuses sparse copy — only written pages are copied (typically 85MB of 256MB) - Hardlinked state:
snapshot.binis hardlinked (17KB, read-only) - Skip health check: Snapshot was taken after app was healthy, so health check is skipped on restore
The gateway includes a built-in real-time dashboard at /dashboard:
- Stats cards: Total instances, idle/busy/paused counts, request throughput, start type breakdowns
- Pool bar: Color-coded visualization of instance states
- Instance table: Per-VM details (ID, IP, state, requests, boot time)
- Event stream: Live log of pool events (scale-up, state changes, request routing)
- Configuration panel: Current gateway settings
The dashboard uses Server-Sent Events (SSE) for real-time updates with no polling.
Run the built-in benchmark to measure boot performance:
npx tsx src/benchmark.ts [image] [cold_runs] [warm_runs] [snapshot_runs]| Start Type | Avg Latency | Description |
|---|---|---|
| Cold boot | ~1,500ms | Full boot: rootfs copy + networking + VM start + health check |
| Snapshot restore | ~300ms | Restore from cached snapshot + resume |
| Warm resume | ~9ms | Resume paused VM from memory |
Warm resume is ~160x faster than cold boot. Snapshot restore is ~5x faster than cold boot.
Run the 5-phase stress test to exercise autoscaling:
npx tsx src/stress.ts http://localhost:9090 --max-concurrency 6 --duration 60| Phase | What it does |
|---|---|
| 1. Ramp Up | Gradually increases concurrency (1 → 3 → 5 → max) |
| 2. Sustained Load | Holds max concurrency for several waves |
| 3. Burst | Spikes to 2x max concurrency (tests queuing) |
| 4. Cool Down | Watches idle → pause → scale-down progression |
| 5. Second Burst | Tests snapshot restores after scale-down |
╔════════════════════════════════════════════════════════════╗
║ AGGRESSIVE STRESS TEST RESULTS ║
╠════════════════════════════════════════════════════════════╣
║ Total requests: 87 ║
║ Succeeded: 87 ║
║ Failed: 0 ║
╠════════════════════════════════════════════════════════════╣
║ Latency p50: 39ms ║
║ Latency p95: 11.59s ║
║ Latency p99: 12.09s ║
╠════════════════════════════════════════════════════════════╣
║ Cold starts: 0 (avg 0ms) ║
║ Warm starts: 7 (avg 9ms) ║
║ Snapshot starts: 10 (avg 473ms) ║
╚════════════════════════════════════════════════════════════╝
| Requirement | Version |
|---|---|
| Linux kernel | 4.14+ with KVM |
| Firecracker | v1.14.2 (auto-downloaded) |
| Guest kernel | vmlinux-6.1.155 (auto-downloaded) |
| Node.js | 20+ |
| Docker | Any recent version |
Each VM slot N is assigned a /30 subnet:
| Slot | TAP | Host IP | Guest IP |
|---|---|---|---|
| 1 | tap_fc1 |
172.16.0.5 | 172.16.0.6 |
| 2 | tap_fc2 |
172.16.0.9 | 172.16.0.10 |
| 3 | tap_fc3 |
172.16.0.13 | 172.16.0.14 |
| ... | ... | ... | ... |
| 63 | tap_fc63 |
172.16.0.253 | 172.16.0.254 |
Up to 63 concurrent VMs are supported.
~/.firecracker-orchestrator/
├── bin/
│ ├── firecracker # Firecracker binary (auto-downloaded)
│ └── kernel/
│ └── vmlinux-6.1.155 # Guest kernel (auto-downloaded)
├── vms/
│ └── {vmId}/
│ ├── metadata.json # VM config & state
│ ├── firecracker.sock # API socket
│ ├── rootfs.ext4 # VM disk
│ └── firecracker.log # FC logs
├── rootfs-cache/ # Built rootfs images (per Docker image)
├── slot-rootfs/ # Stable per-slot rootfs paths
└── snapshots/ # Per-slot snapshot cache
src/
├── cli.tsx # Entry point & command router (React Ink)
├── benchmark.ts # Cold/warm/snapshot boot benchmarks
├── stress.ts # 5-phase autoscaling stress test
├── commands/
│ ├── run.tsx # Create & boot VM
│ ├── list.tsx # List VMs
│ ├── info.tsx # VM details
│ ├── pause.tsx # Pause VM
│ ├── resume.tsx # Resume VM
│ ├── stop.tsx # Stop VM
│ ├── delete.tsx # Delete VM
│ └── serve.tsx # Serverless gateway
├── gateway/
│ ├── pool.ts # Autoscaling pool manager
│ └── server.ts # HTTP reverse proxy + API + SSE
├── lib/
│ ├── config.ts # Paths, versions, constants
│ ├── docker.ts # Docker → ext4 rootfs conversion
│ ├── download.ts # Asset download (FC binary, kernel)
│ ├── firecracker-api.ts # Firecracker socket API client
│ ├── network.ts # TAP/NAT networking
│ ├── snapshot.ts # Per-slot snapshot engine
│ └── vm.ts # VM metadata & filesystem
└── ui/
└── dashboard.ts # React 19 dashboard SPA (inline HTML)
- TLS termination — HTTPS support with auto-cert via Let's Encrypt
- Authentication — API key and JWT auth for gateway and management API
- Rate limiting — Per-client request throttling
- Structured logging — JSON logs with request correlation IDs
- Metrics export — Prometheus
/metricsendpoint with histograms and counters - Graceful drain — Complete in-flight requests before shutdown
- Request retry — Automatic retry on VM failure with circuit breaker
- Crash recovery — Detect and clean up orphaned VMs, TAPs, and sockets on startup
- Resource cleanup — GC for stale snapshots, rootfs cache, and leaked TAP interfaces
- Config file — YAML/TOML config as alternative to CLI flags
- Rolling updates — Swap image version with zero-downtime drain
- Multi-host clustering — Distribute VMs across multiple physical hosts
- Persistent volumes — Mount host directories into VMs for stateful workloads
- CPU pinning — Pin vCPUs to physical cores for consistent performance
- cgroup limits — Per-VM CPU and I/O bandwidth controls
- Network isolation — Per-VM firewall rules and network policies
- Image registry — Pull from remote registries (ECR, GCR, Docker Hub)
- WebSocket proxying — Full duplex WebSocket support through the gateway
-
fcctl ps— Inspect running gateway from a separate terminal -
fcctl logs— Stream VM and gateway logs - Unit & integration tests — Comprehensive test suite with CI pipeline
Built with 🔥 by ParadiseCy