---
title: "Server Configuration"
description: "Server-owned settings.toml sections, CLI overrides, and environment variables"
---

## Config file

`fabro server start` reads `~/.fabro/settings.toml` by default. This is the same file schema used by the CLI.

On a same-machine setup, the CLI and server share one `settings.toml`. On a remote deployment, the server machine has its own `settings.toml`, and the client machine keeps a separate local `settings.toml` for CLI-only values such as `[cli.target]`.

<Note>
Legacy `server.toml`, `user.toml`, and `cli.toml` are ignored with a warning. Rename them to `settings.toml`.
</Note>

### Which sections are server-owned

| Scope | Examples |
|---|---|
| Server-owned (runtime-only from local `settings.toml`) | `[server.listen]`, `[server.api]`, `[server.web]`, `[server.auth]`, `[server.storage]`, `[server.artifacts]`, `[server.slatedb]`, `[server.scheduler]`, `[server.logging]`, `[server.integrations]`, `[features]` |
| Shared run defaults (layered through `.fabro/project.toml`/`workflow.toml`) | `[run.model]`, `[run.prepare]`, `[run.sandbox]`, `[run.checkpoint]`, `[run.inputs]`, `[run.pull_request]`, `[run.git]`, `[run.hooks]`, `[run.agent]` |

The CLI-only `[cli.*]` sections (including `[cli.target]`) belong in the client machine's `settings.toml`. They tell CLI commands how to reach a server. The server process does not read `[cli.*]` for its own binding or routing.

### Full reference

```toml title="settings.toml"
_version = 1

[server.listen]
type = "tcp"
address = "0.0.0.0:3000"

[server.listen.tls]
cert = "/etc/fabro/tls/cert.pem"
key = "/etc/fabro/tls/key.pem"

[server.api]
url = "https://fabro.example.com/api/v1"

[server.web]
enabled = true
url = "https://fabro-web.example.com"

[server.auth]
methods = ["dev-token", "github"]

[server.auth.github]
allowed_usernames = ["alice", "bob"]

[server.integrations.github]
app_id = "123456"
client_id = "Iv1.abc123"

[server.integrations.github.webhooks]
strategy = "tailscale_funnel"

[server.storage]
root = "/var/lib/fabro"

[server.slatedb]
provider = "s3"
disk_cache = true

[server.slatedb.s3]
bucket = "my-fabro-data"
region = "us-east-1"

[server.scheduler]
max_concurrent_runs = 8

[server.logging]
level = "info"

# Run defaults — applied to every run unless overridden by workflow/project config
[run.model]
name = "claude-sonnet-4-5"
provider = "anthropic"
fallbacks = ["gemini", "openai"]

[[run.prepare.steps]]
script = "npm install"

[run.sandbox]
provider = "daytona"

[run.sandbox.daytona]
auto_stop_interval = 60

[run.sandbox.daytona.labels]
team = "platform"

[run.checkpoint]
exclude_globs = ["**/node_modules/**", "**/.cache/**"]

[run.inputs]
default_branch = "main"

[run.git.author]
name = "fabro-bot"
email = "fabro-bot@company.com"

[features]
session_sandboxes = true
```

### CLI overrides

Several `settings.toml` settings can be overridden via `fabro server start` flags:

| Flag | Default | Description |
|---|---|---|
| `--bind` | Resolved `[server.listen]`, falling back to `~/.fabro/fabro.sock` when `[server.listen]` is absent | Address to bind: `IP` or `IP:port` for TCP, or a path for Unix socket |
| `--web` | enabled | Enable the embedded web UI, browser auth routes, and web-only helper endpoints |
| `--no-web` | disabled | Disable the embedded web UI, browser auth routes, and web-only helper endpoints |
| `--foreground` | — | Run in the foreground instead of daemonizing |
| `--model` | — | Override default LLM model |
| `--provider` | — | Override default LLM provider |
| `--sandbox` | — | Override default sandbox provider |
| `--max-concurrent-runs` | `5` | Maximum concurrent run executions |
| `--config` | `~/.fabro/settings.toml` | Path to server config file |

CLI flags take precedence over `settings.toml` values. See [Run Configuration — Precedence](/execution/run-configuration#precedence) for the full resolution order.

### `[server.web]` section

Control the embedded SPA and browser-oriented routes.

| Key | Description | Default |
|---|---|---|
| `enabled` | Serve the embedded SPA, `/auth/*`, and the web-only helper endpoints under `/api/v1` | `true` |
| `url` | External web UI URL used for OAuth redirects | none (no implicit derivation from `server.listen`) |

When `enabled = false`, the server still exposes the machine API and `/health`, but `/`, `/auth/*`, SPA client routes, `/api/v1/auth/me`, `/api/v1/setup/*`, and `/api/v1/demo/toggle` all return `404`.

### `[server.auth]` section

Configure how users authenticate with the server.

| Key | Description | Default |
|---|---|---|
| `methods` | Ordered list of enabled bootstrap methods: `dev-token`, `github` | `["dev-token"]` |

When `"dev-token"` is enabled, the API accepts `Authorization: Bearer fabro_dev_...` and the login page can authenticate with the dev token directly.

When `"github"` is enabled, browser users can sign in with GitHub OAuth and receive a session cookie.

### `[server.auth.github]` section

GitHub-specific auth policy.

| Key | Description |
|---|---|
| `allowed_usernames` | GitHub usernames allowed to complete OAuth login |

The GitHub OAuth client ID still lives under `[server.integrations.github].client_id`.

### `[server.slatedb]` section

Configure the embedded SlateDB key-value store used for run event storage.

| Key | Description | Default |
|---|---|---|
| `provider` | Object store backend: `local` or `s3` | `"local"` |
| `prefix` | Key prefix within the object store | `""` |
| `flush_interval` | How often to flush the write-ahead log | `"1ms"` |
| `disk_cache` | Enable a local disk cache for object store reads | `false` |

When `disk_cache = true`, Fabro creates a cache directory at `<storage_root>/cache/slatedb` and
configures SlateDB to cache object store bytes on local disk (16 GB max, 4 MB parts). This
significantly reduces read latency and costs for S3-backed deployments. A warning is emitted if
enabled with `provider = "local"` since the disk cache adds overhead when the object store is
already local.

```toml title="settings.toml"
[server.slatedb]
provider = "s3"
disk_cache = true

[server.slatedb.s3]
bucket = "{{ env.SLATEDB_BUCKET }}"
region = "us-east-1"
```

### Run defaults

The `[run.*]` sections in `settings.toml` act as defaults for every run.

On a same-machine setup, `settings.toml` is the shared machine-default layer under `workflow.toml` and `.fabro/project.toml`.

On a remote setup, the client bundles workflow, project, and user config into the run manifest. The server then layers those bundled client configs over its own local defaults for run-shaped fields. Server-owned values like `[server.storage]`, `[server.api]`, `[server.web]`, `[features]`, and `[server.scheduler]` always come from the server machine's own `settings.toml` or `fabro server start` flags.

Merge rules follow the normative matrix: `[run.inputs]` replaces wholesale, `[run.sandbox.env]` and `[run.sandbox.daytona.labels]` merge by key, `[run.prepare.steps]` replaces whole-list, and `[[run.hooks]]` merge by optional `id`. Most other fields use "higher-precedence wins" field-wise merging.

### `[server.logging]` section

Configure the default server log level. Precedence: `FABRO_LOG` env var > `--debug` flag > `[server.logging].level` > `"info"`.

| Key | Description | Default |
|---|---|---|
| `level` | Log level: `error`, `warn`, `info`, `debug`, `trace` | `"info"` |

The CLI has its own `[cli.logging]` section.

### `[run.git.author]` section

Customize the git author identity used for checkpoint commits. When not set, defaults to `fabro` / `fabro@local`.

| Key | Description | Default |
|---|---|---|
| `name` | Git author name | `"fabro"` |
| `email` | Git author email | `"fabro@local"` |

### `[server.integrations.github]` section

Configure GitHub integration auth. `strategy = "token"` is the default and uses a stored `GITHUB_TOKEN` from the vault (with `GH_TOKEN` as a fallback). `strategy = "app"` enables the GitHub App flow, browser OAuth, and webhooks.

```toml title="settings.toml"
[server.integrations.github]
strategy = "token"
```

For GitHub App mode, set `strategy = "app"` and include `app_id`, `client_id`, and `slug`. Webhook delivery is configured under `[server.integrations.github.webhooks]`:

```toml title="settings.toml"
[server.integrations.github]
strategy = "app"
app_id = "123456"
client_id = "Iv1.abc123"
slug = "fabro-app"

[server.integrations.github.webhooks]
strategy = "tailscale_funnel"
```

When `webhooks.strategy = "tailscale_funnel"` is configured, `fabro server start` binds a local HTTP listener, exposes it through `tailscale funnel`, and updates the GitHub App's webhook URL on startup. Incoming webhooks are verified with HMAC-SHA256. Requires the `GITHUB_APP_WEBHOOK_SECRET` environment variable.

### `[run.checkpoint]` section

Configure checkpoint behavior for all runs.

| Key | Description |
|---|---|
| `exclude_globs` | Glob patterns for files to exclude from checkpoint commits (for example, `["**/node_modules/**"]`) |

`exclude_globs` replaces across layers — the highest-precedence layer wins wholesale. See [Run Configuration — Checkpoint](/execution/run-configuration#runcheckpoint) for per-run configuration.

### `[features]` section

Toggle experimental or opt-in features. All features default to `false`.

| Key | Description |
|---|---|
| `session_sandboxes` | Enable session sandboxes in the web UI |

The same `[features]` section can be set in `.fabro/project.toml` (project-level) to enable features per-project.

## Secrets and environment variables

Fabro splits secrets into two scopes:

- Server runtime secrets live in `<data_dir>/server.env` and resolve with precedence `process env -> server.env`.
- Workflow-visible secrets live in `<data_dir>/vaults/default/secrets.json` (the vault). Anything stored in the vault may be used by workflows.

For the auth model above, the main server runtime secrets are:

- `SESSION_SECRET` when the web UI is enabled
- `FABRO_DEV_TOKEN` when `"dev-token"` auth is enabled
- `GITHUB_APP_CLIENT_SECRET` when `"github"` auth is enabled
- `FABRO_JWT_PRIVATE_KEY` / `FABRO_JWT_PUBLIC_KEY`, provisioned during install for future CLI login flows

Fabro no longer auto-loads `.env` files. Provider API keys are required for the models you want to use; everything else is optional.

### LLM provider keys

Fabro's built-in provider access resolves these from `process env -> vault`.

| Variable | Provider |
|---|---|
| `ANTHROPIC_API_KEY` | Anthropic (Claude) |
| `OPENAI_API_KEY` | OpenAI (GPT) |
| `GEMINI_API_KEY` or `GOOGLE_API_KEY` | Google (Gemini) |
| `KIMI_API_KEY` | Kimi |
| `ZAI_API_KEY` | Zai (GLM) |
| `MINIMAX_API_KEY` | Minimax |
| `INCEPTION_API_KEY` | Inception (Mercury) |

### Sandbox and tools

| Variable | Description |
|---|---|
| `DAYTONA_API_KEY` | Daytona cloud sandbox API key |
| `BRAVE_SEARCH_API_KEY` | Brave Search API key (for the `web_search` tool) |

### Server authentication

Fabro resolves these from `process env -> server.env`.

| Variable | Description |
|---|---|
| `FABRO_JWT_PRIVATE_KEY` | Ed25519 private key (base64-encoded PEM) for JWT signing |
| `FABRO_JWT_PUBLIC_KEY` | Ed25519 public key (base64-encoded PEM) for JWT verification |
| `SESSION_SECRET` | Session encryption secret (64-character hex string) |

### GitHub integration (optional)

| Variable | Description |
|---|---|
| `GITHUB_TOKEN` | GitHub personal access token, stored by `fabro install` when `strategy = "token"`. Also accepts `GH_TOKEN` as a fallback. |

### GitHub App extras (optional)

Fabro resolves these from `process env -> server.env`.

| Variable | Description |
|---|---|
| `GITHUB_APP_CLIENT_SECRET` | GitHub App client secret |
| `GITHUB_APP_WEBHOOK_SECRET` | GitHub App webhook secret |
| `GITHUB_APP_PRIVATE_KEY` | GitHub App private key (base64-encoded) |

### Slack integration (optional)

| Variable | Description |
|---|---|
| `FABRO_SLACK_APP_TOKEN` | Slack App-level token |
| `FABRO_SLACK_BOT_TOKEN` | Slack Bot token |

### Logging

| Variable | Default | Description |
|---|---|---|
| `FABRO_LOG` | `info` | Log level: `error`, `warn`, `info`, `debug` |
