Skip to content
Fuse
Esc
navigateopen⌘Jpreview
On this page

Deploying the orchestrator

Running the control plane as a long-lived service

For anything past local dev, run the orchestrator as a service rather than a foreground process.

Tokens and ports

Two things cause most bring-up confusion: which token goes where, and which port is which service. State both up front.

There are four distinct tokens, travelling in different directions:

Token Set on Used by Flag / env
Orchestrator bearer Orchestrator you → orchestrator ORCH_AUTH_TOKEN / fuse connect --token
Host agent token Host agent (fc-agent) orchestrator → agent fuse host register --token (the agent’s FC_AGENT_TOKEN)
Host agent token Host agent (qemu-agent) orchestrator → agent fuse host register --token (the agent’s QEMU_AGENT_TOKEN)
API key Orchestrator apps → orchestrator fuse apikeys create

Both host agents take a token the same way, only the env var naming differs per backend, so a GPU host registers with $QEMU_AGENT_TOKEN where a Firecracker host registers with $FC_AGENT_TOKEN.

The single most common setup mistake is passing the host agent token to fuse connect, or the orchestrator token to fuse host register. They are not interchangeable. fuse connect and fuse host register both probe with the token you give them and fail early with a message naming the layer that rejected it, rather than surfacing an opaque 401 one command later.

Default ports:

Port Service
8080 Orchestrator (control plane API)
8090 Firecracker host agent (fc-agent)
8091 GPU/QEMU host agent (qemu-agent)
19551-19799 Per-VM guest-agent DNAT range, Firecracker hosts (fc-agent)
19651-19899 Per-VM guest-agent DNAT range, GPU/QEMU hosts (qemu-agent)

The two DNAT ranges differ because each agent has its own FUSE_HOST_PORT_BASE default, 19550 for fc-agent and 19650 for qemu-agent, and each allocates one port per VM index from 1 to 249. Open the range that matches the backend the host actually runs, rather than assuming one range covers the fleet.

Configuration

Env var Flag Default Purpose
ORCH_LISTEN --listen :8080 API listen address.
FIRECRACKER_BASE_URL --firecracker-url empty → stub Firecracker host agent URL.
FIRECRACKER_TOKEN --firecracker-token Bearer token for the host agent.
DATABASE_URL --database-url empty → in-memory Postgres state store connection string.
TOKEN_ENCRYPTION_KEY Hex-encoded 32-byte AES key for per-VM token encryption at rest.
AGENT_DOWNLOAD_URL URL to fetch the guest agent binary at boot (alternative to baking it in).
ORCH_TLS_CERT / ORCH_TLS_KEY --tls-cert / --tls-key Serve the API over TLS. Setting only one fails at startup.
ORCH_SECURE_COOKIES --secure-cookies empty → derived from TLS Force the Secure flag on session cookies. Set to true when a proxy terminates TLS. See Security hardening.
ORCH_REQUIRE_AUTH false Fail-closed strict mode: refuses to boot unless ORCH_AUTH_TOKEN, TOKEN_ENCRYPTION_KEY, and DATABASE_URL are all set.
ORCH_AUTH_TOKEN --auth-token empty → no auth Static bearer/master token. See Authentication.
ORCH_ALLOWED_CIDRS --allowed-cidrs empty → open Comma-separated CIDR allowlist.
ORCH_SHUTDOWN_TIMEOUT_SECONDS --shutdown-timeout 30 Graceful shutdown ceiling.
ORCH_VM_PREFIX --vm-prefix fuse- Prefix applied to generated VM names.

With FIRECRACKER_BASE_URL unset, the orchestrator runs the in-memory stub provider (fine for local dev, not for production). With DATABASE_URL unset, state is in-memory and does not survive a restart.

Postgres is the source of truth

Fuse doesn’t ship any backup or disaster-recovery tooling of its own, no pg_dump wrapper, no export/import command, no point-in-time-recovery integration. Everything durable (environment records, snapshot metadata, API keys, host registrations) lives in the migrations under internal/orchestrator/migrations/, applied automatically at boot. Treat this Postgres database the same way you’d treat any other production database: standard backup practices apply (pg_dump/pg_restore, WAL archiving, a managed Postgres provider’s automated snapshots, whatever your organization already uses elsewhere). This is general Postgres operational guidance, not something specific to Fuse, there’s no Fuse-side hook or lifecycle event tied to it.

Snapshot restore (fuse snapshot restore, see Snapshots) is an entirely different, VM-level concept, restoring a Firecracker microVM’s disk from a checkpoint. It has no relationship to Postgres backup and doesn’t substitute for one.

Quickest path: co-locate with a Firecracker host

The simplest topology co-locates the orchestrator on a Firecracker host and talks to fc-agent over loopback. The host toolchain installs both as systemd services:

cd host-agent/firecracker
./fc-install.sh                     # firecracker + kernel + rootfs
./fc-agent.sh install-service       # host agent (systemd, :8090)
./fc-agent.sh install-orchestrator  # orchestrator (systemd, :8080), co-located
sudoedit /etc/default/orchestrator  # set DATABASE_URL (postgres)
sudo systemctl start orchestrator

install-orchestrator resolves the orchestrator binary (from ORCH_BIN_SRC=/path, a local ./orchestrator, an existing /usr/local/bin/orchestrator, or the latest GitHub release), writes /etc/default/orchestrator prefilled with FIRECRACKER_BASE_URL=http://127.0.0.1:8090, this host’s FIRECRACKER_TOKEN, and freshly generated ORCH_AUTH_TOKEN + TOKEN_ENCRYPTION_KEY (never overwriting an existing file), then installs orchestrator.service ordered after fc-agent.service.

Auth is on by default: the orchestrator refuses to boot until you supply a Postgres DATABASE_URL. The installer leaves that as a placeholder and does not start the service until you fill it in; the schema is created automatically on first boot.

It then prints the FUSE_BASE_URL and FUSE_TOKEN values for connecting a dashboard, if you’re running one. FUSE_TOKEN must match the orchestrator’s ORCH_AUTH_TOKEN. Open 8080/tcp (or terminate TLS at a reverse proxy and point clients there). Remove the service with ./fc-agent.sh uninstall-orchestrator.

One script: dedicated control-plane host

For a host that runs only the control plane (no co-located agent), use the standalone installer instead:

sudo ./ops/install-orchestrator.sh

It installs the orchestrator binary (from ORCH_BIN_SRC=/path, a local ./orchestrator, or the latest GitHub release), writes /etc/fuse/orchestrator.env with a freshly generated ORCH_AUTH_TOKEN and TOKEN_ENCRYPTION_KEY (never overwriting an existing file), installs and starts fuse-orchestrator.service, and prints the exact fuse connect line to run from your laptop:

orchestrator installed and listening on :8080

  fuse connect http://<this-host>:8080 --token <generated> --master

When the binary comes from a GitHub release, the installer downloads checksums.txt for that exact tag and verifies the archive’s SHA-256 before extracting or installing anything. host-agent/firecracker/fc-update.sh and fc-agent.sh install-orchestrator do the same for every asset they fetch. A missing checksums.txt, a missing entry for the asset, or a mismatch aborts the install, leaving the existing binary in place and the service unrestarted.

The default posture is a single-node, in-memory store with auth on, so it starts immediately. For a durable deploy, set DATABASE_URL in /etc/fuse/orchestrator.env, uncomment ORCH_REQUIRE_AUTH=true, and restart. This is a different unit (fuse-orchestrator.service, config in /etc/fuse/) from the co-located install-orchestrator path above (orchestrator.service, config in /etc/default/orchestrator); use one or the other per host, not both.

Running the orchestrator standalone

To run one control plane scheduling across many hosts instead of co-locating, skip install-orchestrator and point FIRECRACKER_BASE_URL at each host’s agent URL, then register the rest via fuse host register (see Hosts). Topology is just one env var: loopback co-locates, a remote URL doesn’t.

Build and run directly

go build -o bin/orchestrator ./orchestrator
export FIRECRACKER_BASE_URL=http://<host>:<port>
export FIRECRACKER_TOKEN=<token>
export TOKEN_ENCRYPTION_KEY=<hex-encoded 32-byte AES key>
export ORCH_AUTH_TOKEN=<token>
export DATABASE_URL=postgres://...
./bin/orchestrator

Was this page helpful?