Self-hosting
Bring the whole qbox platform up on a single Linux host with one command, behind HTTPS.
qbox runs as a Docker Compose stack on one Linux box with hardware KVM: Postgres, NATS, object storage, the control plane, dashboard, template builder, host agent, and a Caddy reverse proxy that terminates TLS.
Requirements
qbox runs real Firecracker microVMs, so the host must expose hardware
virtualization as /dev/kvm — a bare-metal server, a DigitalOcean Droplet,
an AWS .metal instance, or another VM with nested virtualization enabled. A
plain cloud VM without it won’t spawn sandboxes.
See Requirements for the full list of known-good
instances, how to verify a host, sizing, and filesystem recommendations. In short:
Linux x86_64, /dev/kvm, the tun module, and Docker (the installer handles
TUN and Docker for you).
Install
curl -fsSL https://qbox.sh/install.sh | sh
The installer is idempotent and:
- Verifies the host (Linux,
/dev/kvm, thetunmodule) and installs Docker if it isn’t present. - Ensures the firecracker and jailer binaries are staged (downloads the pinned official release if missing).
- Downloads the guest kernel (
vmlinux), the qboxd guest agent, and dropbear into./assets. - Downloads the latest
docker-compose.yml. - Generates a
.envwith strong random secrets on first run (it never overwrites an existing.env). - Pulls the published images and brings the stack up.
When it finishes, open the URL it prints and complete the install flow to create the first admin user.
Override defaults with environment variables, e.g.:
curl -fsSL https://qbox.sh/install.sh | QBOX_SITE_ADDRESS=qbox.acme.com QBOX_DATA_DIR=/mnt/data/qbox sh
HTTPS / TLS
TLS is handled by Caddy and driven by a single variable, QBOX_SITE_ADDRESS:
| You set | What happens |
|---|---|
A real domain (qbox.acme.com) | Automatic Let’s Encrypt certificate, auto-renewed. |
An IP address or left as :443 | Caddy serves a self-signed cert from its internal CA. |
QBOX_TLS_CERT + QBOX_TLS_KEY | Caddy uses your certificate and key (mounted into the proxy). |
Caddy listens on 443 and redirects 80 → 443. To bring your own cert, drop
tls.crt and tls.key into the TLS directory (QBOX_TLS_DIR, default ./tls)
and the proxy uses them automatically.
Point DNS first. Let’s Encrypt only issues a certificate once your domain already resolves to this host. Before (or right at) install, add an A/AAAA record for
qbox.acme.compointing at the host’s public IP, and make sure ports 80 and 443 are open to the internet. If you open the site and see a certificate error, DNS isn’t pointing here yet (or 80/443 is blocked) — fix that and Caddy obtains the cert within seconds, no restart needed.
Choosing where data lives
All persistent state lives under QBOX_DATA_DIR (default /var/lib/qbox):
Postgres, NATS, object storage, the builder workspace, and the host-agent cache.
Point it at a large, reflink-capable disk:
QBOX_DATA_DIR=/mnt/volume_xfs/qbox
The installer creates the subdirectories; changing it later means moving the data
and updating .env.
Build your first template
- Templates → New in the dashboard. Give it a public image such as
python:3.12. The builder pulls it, builds a rootfs, boots and snapshots a microVM, and uploads the artifacts. Wait for ready (watch the build log) — a build can take several minutes, and longer for a large image or on a slow disk. - Sandboxes → Spawn: pick the template. It moves
pending → booting → running. - Use Logs and Files; if the template enabled SSH, the Shell tab opens an interactive session inside the VM.
Build & first-spawn cost. Building a template is CPU- and I/O-heavy — it pulls the image, builds an ext4 rootfs, and boots a microVM to snapshot it — so expect it to use real host CPU (size the host accordingly, and note
QBOX_BUILDER_CONCURRENCYruns builds in parallel). A single build can take several minutes, and longer for a large image or on a slow disk. The first spawn of a freshly-built template also pulls its rootfs/snapshot/kernel from object storage into the host’s local cache, which can take several seconds for a large image; a spawn issued immediately after the build waits on that pull. Subsequent spawns are warm (served from cache).
Updating
Re-run the installer — it re-downloads the latest docker-compose.yml, pulls the
new images, and recreates changed services. Your .env and data are left intact.
curl -fsSL https://qbox.sh/install.sh | sh
Or, in the install directory:
docker compose pull && docker compose up -d
Operating the stack
# follow logs
docker compose logs -f control-plane host-agent
# stop / start (keeps data)
docker compose down
docker compose up -d
# stop and DELETE all data
docker compose down -v
Adding capacity
The single-host stack runs one host agent on the same box. To add more capacity, run the host-agent image on additional KVM hosts pointed at the same NATS and object storage. See Configuration for the host-agent variables.
Note: because Firecracker processes are children of the host-agent container, restarting it stops running microVMs (their sandboxes are marked terminated). For VMs that survive agent restarts, run the host agent under systemd instead of Docker.