docker compose. The repo ships everything you need:
docker-compose.yamlpulls the pre-built image from GHCR and declares a named volume for/storagedocker-compose.prod.yamladds a Caddy sidecar that terminates TLS and auto-provisions Let’s Encrypt certificatesdocker/Caddyfilereverse-proxies HTTPS traffic to the Fabro server
Why not App Platform? DigitalOcean App Platform has no persistent volumes — it is designed for stateless workloads that offload state to managed Postgres or Spaces. Fabro writes runs, checkpoints, sessions, and JWT keys to
/storage, so a Droplet (or any VPS) is the right fit. If you prefer Kubernetes, DOKS works too — that path is not documented here.Prerequisites
- A DigitalOcean account and (optionally) the
doctlCLI - A domain name with DNS you can edit (required for Caddy to issue a Let’s Encrypt cert)
- LLM provider API keys (Anthropic, OpenAI, etc.) and any secrets you want set via
.env
1. Create a Droplet
Pick the Docker on Ubuntu image from the DigitalOcean Marketplace — it ships with Docker Engine and the Compose plugin preinstalled, so there’s no manual Docker install step. From the control panel, or withdoctl:
s-2vcpu-2gb is a reasonable starting size for light usage; grow later as your workflow load increases. Any region works — pick the one closest to you.
2. Point DNS at the Droplet
Caddy needs the domain to resolve to the Droplet’s public IP before you start the stack, or the first cert issuance will fail. Create anA record for your chosen hostname (e.g. fabro.example.com) pointing at the Droplet’s IPv4 address. Wait for propagation before continuing.
3. Configure and launch
SSH into the Droplet and pull the repo:.env. At minimum:
| Variable | Purpose |
|---|---|
FABRO_DOMAIN | Public hostname Caddy serves. Must resolve to this Droplet for Let’s Encrypt to issue a cert. |
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 |
fabro (the server, state in the fabro-storage named volume) and caddy (listening on ports 80/443, cert state in the caddy_data named volume). Caddy requests a Let’s Encrypt cert on first boot; watch progress with docker compose logs -f caddy.
Accessing your Fabro server
Oncehttps://<FABRO_DOMAIN>/health returns ok, two things to grab:
-
The dev token — on first boot, Fabro writes one to
/var/fabro/dev-tokenand logs it: -
Point your local CLI at the server — add the URL to
~/.fabro/settings.toml:Then commands like~/.fabro/settings.tomlfabro model list --server <url>will hit your Droplet.
Updates
To pull the latest nightly image and restart:fabro-storage and caddy_data named volumes survive pull and up, so runs, checkpoints, and TLS certs persist.
To pin a specific version instead of :nightly, edit docker-compose.yaml and change image: ghcr.io/fabro-sh/fabro:nightly to the tag you want.
Caveats
- DNS must resolve before first
up. Caddy will retry Let’s Encrypt failures, but an obviously bad DNS config will lock you into the staging CA’s low rate limits. Verify withdig +short fabro.example.combefore starting. - Firewall. The Docker Marketplace image opens 22, 80, and 443 by default — good. Keep port 32276 closed on the public interface; Caddy fronts the Fabro server on the private Docker network. Use
ufw statusto verify. - State lives in named volumes.
fabro-storageandcaddy_dataare the load-bearing pieces. Back them up (for example, viadocker run --rm -v fabro_fabro-storage:/src -v $(pwd):/dst alpine tar czf /dst/backup.tgz -C /src .) before destructive operations. - Single-host deploy. This setup assumes one Droplet owns the data. For HA you’d need a different architecture (external block storage, managed DB, etc.) — Fabro’s server currently assumes a single writer on
/storage. - Architecture. The compose file pins
platform: linux/amd64; the:nightlytag is multi-arch but the arm64 variant is not currently usable. Use x86_64 Droplets.
Next steps
Running the Fabro Server
Auth, dev tokens, submitting runs, and pointing the CLI at your deployment.
Server Configuration
Full
settings.toml reference — reverse-proxy TLS, auth methods, concurrency, and more.