diff --git a/docs/administration/deploy-fly-io.mdx b/docs/administration/deploy-fly-io.mdx index 154f7a67f..cf3c4e61b 100644 --- a/docs/administration/deploy-fly-io.mdx +++ b/docs/administration/deploy-fly-io.mdx @@ -1,8 +1,107 @@ --- title: "Fly.io" -description: "Deploy Fabro to Fly.io" +description: "Deploy Fabro to Fly.io from the prebuilt GHCR image, with a Fly Volume for state" --- -This guide is coming soon. Deployment guides are currently in development. + The server interface is in private early access. Contact [bryan@qlty.sh](mailto:bryan@qlty.sh) if you're interested in trying it. + +[Fly.io](https://fly.io) can host the Fabro server by pulling the pre-built image published to GHCR. The repo ships a `fly.toml` that points Fly directly at the image — no build step on Fly's builders, no `Dockerfile` evaluation — and declares a Volume mount at `/storage` so your runs, checkpoints, and sessions survive redeploys. + +Fly.io is CLI-first; there is no one-click deploy button. The workflow below uses [`flyctl`](https://fly.io/docs/flyctl/install/). + +## First-deploy checklist + +### 1. Adopt `fly.toml` in a new app + +```bash +git clone https://github.com/fabro-sh/fabro +cd fabro +fly launch --copy-config --no-deploy +``` + +`fly launch --copy-config` keeps the repo's `fly.toml` instead of generating a new one; `--no-deploy` lets you finish wiring secrets and volumes before the first deploy. You'll be prompted for an **app name** (must be globally unique on Fly) and a **primary region** — update `fly.toml` in place if you change the defaults. + +### 2. Create the persistent Volume + +Fabro writes all persistent state — run history, checkpoints, sessions, the default token, and JWT keys — under `/storage`. Fly containers have ephemeral filesystems, so without a Volume that directory is wiped on every redeploy. `fly.toml` declares the mount but **cannot create the volume itself** — provision it with `flyctl`: + +```bash +fly volumes create storage --size 1 --region +``` + +Grow later with `fly volumes extend` if needed. The volume name (`storage`) must match `[[mounts]].source` in `fly.toml`. + +### 3. Set required environment variables + +Fly stores env vars as encrypted secrets: + +```bash +fly secrets set \ + ANTHROPIC_API_KEY=... \ + SESSION_SECRET=... +``` + +The [Server Configuration](/administration/server-configuration) reference has the full list; the minimum useful set: + +| Variable | Purpose | +|---|---| +| `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` / `GEMINI_API_KEY` / ... | At least one LLM provider key for the models you'll run | +| `FABRO_DEV_TOKEN` | Optional — pre-set the dev token instead of reading the one written to `/storage` on first boot | +| `SESSION_SECRET` | 64-character hex string; required when the web UI is enabled | +| `GITHUB_APP_CLIENT_SECRET`, `GITHUB_APP_WEBHOOK_SECRET`, `GITHUB_APP_PRIVATE_KEY` | Only if you enable GitHub OAuth or the GitHub App integration | + +### 4. Deploy + +```bash +fly deploy +``` + +Fly pulls `ghcr.io/fabro-sh/fabro:nightly`, attaches the volume, and starts the Machine. The health check on `/health` must pass before traffic is routed. + +## Accessing your Fabro server + +Once the deploy is healthy, Fly exposes a `.fly.dev` URL (or your custom domain). Two things to grab: + +1. **The dev token** — on first boot, Fabro writes one to `/var/fabro/dev-token` and logs it. Read it via the Machine's shell: + + ```bash + fly ssh console -C "cat /var/fabro/dev-token" + ``` + + Or tail the startup logs with `fly logs`. + +2. **Point your local CLI at the server** — add the Fly URL to `~/.fabro/settings.toml`: + + ```toml title="~/.fabro/settings.toml" + [server] + target = "https://.fly.dev/api/v1" + ``` + + Then commands like `fabro model list --server ` will hit your Fly instance. + +See [Running the Fabro Server](/administration/deploy-server) for the full auth and CLI-pointing story. + +## Redeploys and updates + +`fly deploy` re-pulls the GHCR image on every run. `fly.toml` references the `:nightly` tag by default, so redeploying picks up the latest nightly automatically. To pin a specific version, edit `fly.toml` to reference `ghcr.io/fabro-sh/fabro:` and redeploy. The `/storage` Volume survives redeploys, so runs and checkpoints persist. + +## Caveats + +- **`$PORT` is not injected.** Unlike Railway and Render, Fly does not set a `PORT` environment variable. The Fabro image binds to `$PORT` if set, otherwise `32276` — `fly.toml` pins `internal_port = 32276` so the default works. If you change `internal_port`, also `fly secrets set PORT=` to match. +- **Volume is load-bearing and not replicated.** Fly's docs recommend at least two Volumes per app for redundancy, but Fabro's server is single-replica by design — one Machine owns `/storage`. Treat this like a traditional VPS: hardware failure means restoring from [Fly's volume snapshots](https://fly.io/docs/volumes/snapshots/) or a backup you manage. +- **Single Machine.** Don't `fly scale count` above 1 — a second Machine can't mount the same Volume, and the server assumes a single writer. +- **Architecture.** Fly Machines run x86_64 (amd64) by default. The `:nightly` tag is multi-arch, but the arm64 variant is not currently usable — stay on amd64. +- **Autostop is disabled.** `fly.toml` sets `auto_stop_machines = "off"` so the Machine stays up for the run queue. Leaving autostop enabled would pause Fabro when there's no HTTP traffic, stalling any in-flight runs. + +## Next steps + + + + Auth, dev tokens, submitting runs, and pointing the CLI at your deployment. + + + Full `settings.toml` reference — TLS, auth methods, concurrency, and more. + + diff --git a/fly.toml b/fly.toml new file mode 100644 index 000000000..58a9f8fdd --- /dev/null +++ b/fly.toml @@ -0,0 +1,35 @@ +# Fly.io deployment config for the Fabro server. +# +# Pulls the multi-arch image published to GHCR instead of building from +# source on every deploy. Persists state to a Fly Volume mounted at +# /storage. The Fabro binary binds to $PORT or 32276, so matching +# internal_port to 32276 avoids needing to wire PORT as a secret. +# +# First-time setup: +# fly launch --copy-config --no-deploy # adopts this file; sets app name/region +# fly volumes create storage --size 1 # required — fly.toml cannot create volumes +# fly secrets set ANTHROPIC_API_KEY=... SESSION_SECRET=... +# fly deploy + +app = "fabro" +primary_region = "ord" + +[build] + image = "ghcr.io/fabro-sh/fabro:nightly" + +[[mounts]] + source = "storage" + destination = "/storage" + +[http_service] + internal_port = 32276 + force_https = true + auto_stop_machines = "off" + auto_start_machines = false + + [[http_service.checks]] + path = "/health" + method = "GET" + interval = "30s" + timeout = "5s" + grace_period = "10s"