---
title: "Configure Service Environment"
url: "https://docs.caracal.run/operations/env-vars/"
markdown_url: "https://docs.caracal.run/markdown/operations/env-vars.md"
description: "Operational environment variables for Caracal services and runtime workloads."
page_type: "reference"
concepts: []
requires: []
---

# Configure Service Environment

Canonical URL: https://docs.caracal.run/operations/env-vars/
Markdown URL: https://docs.caracal.run/markdown/operations/env-vars.md
Description: Operational environment variables for Caracal services and runtime workloads.
Page type: reference
Concepts: none
Requires: none

---

Caracal services load configuration from environment variables and `*_FILE` secret variants. Use file-backed secrets in `rc` and `stable` modes.

## Mode Requirements

`CARACAL_MODE` selects one of two security postures, not three:

- **`dev`** — the only relaxed posture. Permits local conveniences (open metrics, `INSECURE_*` overrides, generated/relaxed settings) for development on a single host. Never use it for anything reachable by others.
- **Published (`rc` and `stable`)** — the production posture. Both are **security-identical and fail-closed**: valid HMAC keys are required, Gateway fail-open settings are denied, and incomplete service configuration is rejected before readiness succeeds.

The difference between `rc` and `stable` is **maturity, not security**. `rc` is a release-candidate build that enforces the full production trust boundary but may be functionally unstable; run `stable` for production workloads and reserve `rc` for staging or pre-release validation.

| Mode | Posture | Use for |
| --- | --- | --- |
| `dev` | Relaxed (single-host only) | Local development |
| `rc` | Published — fail-closed, may be functionally unstable | Staging / pre-release validation |
| `stable` | Published — fail-closed | Production |

Published modes require valid HMAC keys, deny unsafe Gateway fail-open settings, and reject incomplete service configuration before readiness succeeds.

## Shared Service Variables

| Variable | Mode | Used by | Meaning |
| --- | --- | --- | --- |
| `CARACAL_MODE` | all | All services | `dev`, `rc`, or `stable`. |
| `PORT` | all | HTTP services | Fixed service port: API `3000`, STS `8080`, Gateway `8081`, Audit `9090`, Coordinator `4000`, Web Console BFF `3002`. Control runs in-process in API. |
| `HOST` | all | TypeScript services | Bind host; defaults to `0.0.0.0` in published modes. |
| `LOG_LEVEL` | all | Services | Log verbosity. |
| `DATABASE_URL` / `DATABASE_URL_FILE` | all | API, STS, Gateway, Audit, Coordinator | Postgres connection for product, policy, audit, and delegation state. |
| `REDIS_URL` / `REDIS_URL_FILE` | all | API, STS, Gateway, Audit, Coordinator | Redis connection. |
| `STREAMS_HMAC_KEY` / `STREAMS_HMAC_KEY_FILE` | rc+stable | API, STS, Gateway, Coordinator | Signs Redis stream messages. |
| `AUDIT_HMAC_KEY` / `AUDIT_HMAC_KEY_FILE` | rc+stable | API, STS, Gateway, Audit, Control | Signs or verifies audit events. |
| `METRICS_BEARER` / `METRICS_BEARER_FILE` | rc+stable | STS, Gateway, API, Audit, Coordinator | Metrics endpoint bearer token. Generated as the managed `metricsBearer` secret by `caracal up`; in published mode (`rc`/`stable`) the metrics endpoints fail closed (401) without it. |

## Service-Specific Variables

| Service | Variables |
| --- | --- |
| API | `CARACAL_ADMIN_TOKEN`, `ZONE_KEK`, `GATEWAY_STS_HMAC_KEY`, `STS_URL`, `API_BODY_LIMIT_BYTES`, `API_V1_RATE_LIMIT_PER_MIN`, `API_READY_OUTBOX_DEAD_MAX`, `TRUST_PROXY`, `CARACAL_CONTROL_ENABLED`, `AUDIT_HMAC_KEY`, `API_OPERATOR_*` |
| STS | `ISSUER_URL`, `ZONE_KEK`, `ZONE_KEK_PROVIDER`, `GATEWAY_STS_HMAC_KEY`, `STS_ADMIN_TOKEN`, `MAX_GRANT_TTL_SECONDS`, `OPA_POLL_SECONDS`, `AUDIT_REPLAY_DIR` |
| Gateway | `STS_URL`, `GATEWAY_STS_HMAC_KEY`, `UPSTREAM_HOST_ALLOWLIST`, `TLS_CERT_FILE`, `TLS_KEY_FILE`, `MAX_REQUEST_BYTES`, `JTI_FAIL_OPEN`, `AUDIT_REPLAY_DIR` |
| Audit | `AUDIT_ADMIN_TOKEN`, `AUDIT_RETENTION_DAYS`, `AUDIT_MAX_DELIVERIES`, `AUDIT_CLAIM_IDLE_SECS`, `AUDIT_TAMPER_ROLLING_HOURS`, `AUDIT_EXPORT_S3_*`, readiness thresholds |
| Coordinator | `ISSUER_URL`, `STS_URL`, `AGENT_COORDINATOR_SCOPE`, `CARACAL_COORDINATOR_TOKEN`, sweep intervals, retention windows, rate limits |
| Web Console (BFF) | `CARACAL_AUTH_DATABASE_URL`, `CARACAL_AUTH_SECRET`, `CARACAL_AUTH_DATABASE_SSL`, `CARACAL_AUTH_SECURE_COOKIES`, `CARACAL_AUTH_URL`, `CARACAL_WEB_ORIGIN`, `CARACAL_WEB_ROOT`, `CARACAL_AUTH_AUTO_MIGRATE`, `CARACAL_API_URL`, `CARACAL_COORDINATOR_URL`, `CARACAL_ADMIN_TOKEN`, `CARACAL_COORDINATOR_TOKEN`, `PORT`, `HOST`, `LOG_LEVEL` |
| Control | `STS_JWKS_URL`, `STS_ISSUER_URL`, `CONTROL_AUDIENCE`, `CONTROL_REDIS_URL`, `CONTROL_API_TOKEN`, `CARACAL_API_URL`, rate and replay controls |

### Web Console (BFF)

The `caracal-web` image runs the session-guarded backend-for-frontend and serves the built SPA from the same origin. It holds server-side control-plane tokens and proxies browser requests to the internal API and Coordinator; those tokens are never exposed to the browser.

| Variable | Required | Default | Meaning |
| --- | --- | --- | --- |
| `CARACAL_AUTH_DATABASE_URL` / `CARACAL_AUTH_DATABASE_URL_FILE` | yes | none | Postgres connection for the dedicated Better Auth session store. Helm and Compose use the separate `caracal_auth` database through the `authDatabaseUrl` secret key. |
| `CARACAL_AUTH_SECRET` / `CARACAL_AUTH_SECRET_FILE` | yes | none | Better Auth signing secret. `caracal web` provisions it for local development; production deployments must provide a high-entropy secret. |
| `CARACAL_AUTH_DATABASE_SSL` | no | `require` in production, `disable` in development | Postgres TLS mode: `disable`, `require`, or `no-verify`. An explicit value always wins. |
| `CARACAL_AUTH_SECURE_COOKIES` | no | enabled in production and for `https://` base URLs | Forces the session cookie `Secure` attribute. |
| `CARACAL_AUTH_URL` | production yes | `http://localhost:<PORT>` | Public HTTPS origin browsers load. In the packaged same-origin deployment this is also the trusted browser origin. |
| `CARACAL_WEB_ORIGIN` | no | `http://localhost:3001` plus `CARACAL_AUTH_URL` origin | Comma-separated extra trusted browser origins for split deployments. |
| `CARACAL_WEB_ROOT` | no | unset | Filesystem path of the built SPA the BFF serves. The production image sets `/app/auth/web`; leave unset for a pure BFF in a split deployment. |
| `CARACAL_AUTH_AUTO_MIGRATE` | no | `false` in production, `true` in development | Runs Better Auth schema provisioning on boot. Keep it `false` for multi-replica deployments and run `node dist/migrate.js` once from the BFF image. |
| `CARACAL_API_URL` | yes | `http://localhost:3000` behavior is only suitable for local single-host use | Internal API endpoint proxied by the BFF. |
| `CARACAL_COORDINATOR_URL` | yes | `http://localhost:4000` behavior is only suitable for local single-host use | Internal Coordinator endpoint proxied by the BFF. |
| `CARACAL_ADMIN_TOKEN` / `CARACAL_ADMIN_TOKEN_FILE` | yes | none | Server-side API token held by the BFF. |
| `CARACAL_COORDINATOR_TOKEN` / `CARACAL_COORDINATOR_TOKEN_FILE` | yes | none | Server-side Coordinator token held by the BFF. |
| `PORT` | no | `3002` | BFF listen port. Prefer `PORT`; `CARACAL_AUTH_PORT` is a legacy fallback. |
| `HOST` | no | `0.0.0.0` in production, `127.0.0.1` in development | BFF bind host. |
| `LOG_LEVEL` | no | `info` | BFF log verbosity. |

### API Operator and Control

The API service runs the Control plane in-process and powers the Caracal Operator console capability. Control is off until enabled, and the Operator runs without natural-language assistance until at least one AI provider is configured. Provider keys are read from the API service environment and never returned to the browser.

| Variable | Required | Default | Meaning |
| --- | --- | --- | --- |
| `CARACAL_CONTROL_ENABLED` | no | `false` | Enables the in-process Control plane the Operator executes through. |
| `CONTROL_GATE_FILE` | no | unset | Path to a file that gates Control exposure. |
| `AUDIT_HMAC_KEY` | rc/stable when Control is enabled | none | Hex-encoded key (≥32 bytes) for tamper-evident admin audit. Required when `CARACAL_CONTROL_ENABLED=true` in published modes. |
| `API_OPERATOR_ENABLED` | no | `true` | Enables the Caracal Operator console capability. |
| `API_OPERATOR_AI_PROVIDERS` | no | unset | Comma-separated provider ids in failover order. With none set, the Operator runs without natural-language assistance. |
| `API_OPERATOR_AI_<ID>_BASE_URL` | per provider | none | OpenAI-compatible base URL for provider `<ID>`. |
| `API_OPERATOR_AI_<ID>_MODEL` | per provider | none | Model name for provider `<ID>`. |
| `API_OPERATOR_AI_<ID>_API_KEY` | hosted providers | none | API key for provider `<ID>`. |
| `API_OPERATOR_AI_<ID>_TIMEOUT_MS` | no | `30000` | Per-request timeout for provider `<ID>`. |
| `API_OPERATOR_AI_<ID>_CONTEXT_WINDOW` | no | `0` | Context-window hint for provider `<ID>`; `0` leaves it unset. |
| `API_OPERATOR_AI_MAX_OUTPUT_TOKENS` | no | `4096` | Per-call ceiling on generated tokens. |
| `API_OPERATOR_AI_MAX_CALLS_PER_TURN` | no | `12` | Per-turn budget on model calls. |
| `API_OPERATOR_LLM_PROXY_URL` | no | `http://litellm:4000/v1` | Default OpenAI-compatible proxy endpoint. |
| `API_OPERATOR_SELF_GOVERN` | no | `false` | Lets the Operator self-govern the `caracal.sys` system zone; requires the Control plane and the sealed control secret. |
| `API_OPERATOR_CONTROL_CLIENT_SECRET` | no | none | Sealed control secret for the Operator's governed execution. |
| `API_OPERATOR_ALLOWED_CAPABILITIES` | no | built-in set | Overrides the Operator's state-changing capability allowlist. |
| `API_OPERATOR_SYSTEM_ZONES` | no | empty | Additional zones marked as system zones the Operator must not act in. |
| `API_OPERATOR_AUTOPILOT_ENABLED` | no | `false` | Master switch; when on, an agent-mode conversation that engages autopilot has every plan auto-approved. The governed execute path still enforces the capability allowlist, least-privilege token, and zone isolation. |

## Runtime Workload Variables

These variables belong to `caracal run` and SDK profile loading, not to service deployment:

| Variable | Meaning |
| --- | --- |
| `CARACAL_CONFIG` | Explicit runtime profile path. |
| `CARACAL_STS_URL` or `CARACAL_ZONE_URL` | Cloud/custom STS URL override for token exchange. |
| `CARACAL_GATEWAY_URL` | Cloud/custom Gateway URL override for SDK transports. |
| `CARACAL_ZONE_ID` | Zone identifier. |
| `CARACAL_APPLICATION_ID` | Confidential application ID. |
| `CARACAL_APP_CLIENT_SECRET` | Cloud/custom workload client secret when a file-backed secret is not used. |
| `CARACAL_APP_CLIENT_SECRET_FILE` | Cloud/custom workload secret file. |
| `CARACAL_RUN_CREDENTIALS` | Inline JSON credential manifest for resource audiences. |
| `CARACAL_RUN_CREDENTIALS_FILE` | Cloud/custom JSON credential manifest. |
| `CARACAL_RESOURCES` | Comma-separated `resource_id=upstream_prefix` bindings for Gateway routing. |
| `CARACAL_RESOURCES_FILE` | JSON resource binding file for Gateway routing. |

Local dev and stable runtime launches auto-detect credential files from the OS
Caracal config directory. Use the explicit file variables only when a deployment
mounts secrets somewhere else.

Resource binding files may contain either a flat JSON object such as
`{"calendar":"https://api.example.com/v1"}` or an array of
`{"resource_id":"calendar","upstream_prefix":"https://api.example.com/v1"}`
objects. When both resource variables are set, entries in `CARACAL_RESOURCES`
override matching entries from `CARACAL_RESOURCES_FILE`.

Local dev and stable runtime launches also resolve service URLs automatically.
Use explicit service URL variables only when a deployment does not use the local
stack defaults.

## Published-Mode Rules

Before a published deployment becomes ready:

1. `GATEWAY_STS_HMAC_KEY` must be hex-encoded and at least 32 bytes for STS and Gateway.
2. `AUDIT_HMAC_KEY` must be present for Audit, Gateway, and Control.
3. Gateway must not run with `JTI_FAIL_OPEN=true`.
4. Gateway allows operator-provisioned private upstreams by default; set `UPSTREAM_HOST_ALLOWLIST` to pin egress to named hosts.
5. STS caps `OPA_POLL_SECONDS` at `300`.

## Troubleshooting

| Symptom | Check |
| --- | --- |
| A service starts locally but fails in Helm | Published modes require stricter HMAC, URL, and secret validation. |
| File secret is ignored | Confirm the variable uses the `*_FILE` suffix supported by that service. |
| Wrong port error | Use the fixed port for the service; several services reject arbitrary `PORT` values. |
| Runtime workload cannot find config | Use [Configure Workloads](/runtime-console/config-file/) rather than service env vars. |

## Next Step

Use [Harden Production](/operations/tls-hardening/) to confirm published-mode, network, secret, and upstream safety settings.
