Environment variables
Resuma ships secure defaults for local development — you do not need any env vars to run cargo run or resuma dev. Production settings are mostly automatic when you scaffold with resuma new --template production (Fly fly.toml included).
Runtime env (this server)
Live snapshot from this server process (no secrets) — compare with resuma doctor.
RESUMA_ENV— RESUMA_TRUST_PROXY— - rate backend
— - CSRF
— - origin check
—
What you need, by app type
| App type | Local dev | PaaS / Docker prod |
|---|---|---|
| SSR / Flow only No .workers() | Nothing required | RESUMA_ENV + RESUMA_TRUST_PROXY + RESUMA_TRUSTED_PROXY_CIDRS(see Deploy) |
| + Resuma OS workers Queue, scheduler, graphs | RESUMA_EXEC_PUBLIC=1or set RESUMA_EXEC_API_KEY | Above + RESUMA_EXEC_API_KEY(use fly secrets set) |
| Production template /ops dashboard | — | Also RESUMA_OPS_SESSION |
The three variables everyone asks about
RESUMA_RATE_BACKEND and RESUMA_DATA_DIR
Rate limiting is built in — no Redis required. Dev uses an in-memory sliding window; production automatically switches to a disk backend under {RESUMA_DATA_DIR}/rate-limit/ (exclusive file locks, safe across multiple processes on the same volume).
RESUMA_RATE_BACKEND=memory # dev (default)
RESUMA_RATE_BACKEND=disk # prod (auto when RESUMA_ENV=production)
RESUMA_DATA_DIR=/data # must be writable by the process user (not /app/.resuma)In Docker, mkdir /data && chown 65532:65532 /data before USER 65532. If this directory is not writable, production rate limits fail and #[server] actions return 500. A Fly volume is only needed if the data must survive a new machine.
Tune limits: RESUMA_RATE_ACTIONS=120, RESUMA_RATE_SUBMITS=60. Legacy RESUMA_RATE_BACKEND=redis is ignored — use disk or edge rate limiting for multi-machine deploys.
RESUMA_ENV=production
Turns on production mode:
- Generic error messages to clients (no internal details leaked)
- Disk-backed rate limiting (survives restarts, shared across processes on the same volume)
- Hides
/_resuma/benchmark.json - Stricter origin validation on form submits and actions
- CSP enforced (unless disabled)
When: real deploys only. Local: omit it — dev defaults are intentional.
RESUMA_TRUST_PROXY=1
Trust X-Forwarded-For and X-Forwarded-Proto from your reverse proxy (Fly.io, DigitalOcean, nginx, Caddy, Cloudflare). Needed for:
- Correct HTTPS detection → HSTS, Secure cookies
- Real client IP for rate limiting
You must also set RESUMA_TRUSTED_PROXY_CIDRS (comma-separated). Without it, serve() exits. Fly: fdaa::/16. App Platform / Railway-style private fabric: start with 10.0.0.0/8. nginx on localhost: 127.0.0.1/32.
When: only behind a reverse proxy. Never on bare cargo run without a proxy in front.
RESUMA_EXEC_API_KEY
Secret for admin exec routes: /_resuma/worker, /_resuma/queue, scheduler, webhooks, metrics, status. Resuma is fail-closed — without a key, these routes return 401.
When: only if your app registers workers via .workers(registry). Pure SSR/Flow apps never mount exec routes and do not need this key.
openssl rand -hex 32
# Fly:
fly secrets set RESUMA_EXEC_API_KEY=$(openssl rand -hex 32)Send on requests: Authorization: Bearer <key> or header X-Resuma-Exec-Key.
Automatic vs manual
| Variable | Automatic? | Notes |
|---|---|---|
RESUMA_ENV | Partial | resuma new --template production writes it in fly.toml |
RESUMA_TRUST_PROXY | Partial | Same — included in production scaffold |
RESUMA_TRUSTED_PROXY_CIDRS | No | Required when trust-proxy is on. Fly fdaa::/16 — see Deploy |
RESUMA_EXEC_API_KEY | No | Must be a unique secret per app. Set via fly secrets or your platform's secret store |
CSRF, origin check, CSP | Yes | On by default — no env vars needed |
Exec routes /_resuma/* | Yes | Only mounted when .workers() is used or RESUMA_EXEC_ENABLED=1 |
Local development with workers
For exec routes without managing an API key locally:
RESUMA_EXEC_PUBLIC=1 cargo runIgnored when RESUMA_ENV=production — production always requires a real key.
Production scaffold
resuma new my-app --template production generates a Dockerfile and fly.toml. Full walkthroughs (Fly, DigitalOcean App Platform, Droplet, Railway, Render): Deploy.
# fly.toml — already included
[env]
RESUMA_ENV = "production"
RESUMA_ADDR = "0.0.0.0:8080"
RESUMA_TRUST_PROXY = "1"
RESUMA_TRUSTED_PROXY_CIDRS = "fdaa::/16"
RESUMA_DATA_DIR = "/data"
CARGO_MANIFEST_DIR = "/app"
[http_service]
internal_port = 8080
force_https = trueThen deploy (--ha=false = one machine):
fly launch --no-deploy --ha=false
fly secrets set RESUMA_EXEC_API_KEY=$(openssl rand -hex 32) # only if using .workers()
fly deploy --ha=falseFull reference
Common server variables (CSRF, rate limits, CSP):
RESUMA_CSRF=1 # default on
RESUMA_ORIGIN_CHECK=1 # default on
RESUMA_BODY_LIMIT=1048576
RESUMA_RATE_ACTIONS=120
RESUMA_RATE_SUBMITS=60
RESUMA_RATE_BACKEND=memory|disk # disk auto in production — no Redis
RESUMA_DATA_DIR=/data # writable; rate-limit/, queue/, durable/
CARGO_MANIFEST_DIR=/app # Docker: public/ lives next to the binary
RESUMA_CSP=1 # off in RESUMA_DEV unless RESUMA_CSP_DEV=1; set 0 to embed YouTube/frames
SITE_URL=https://your-app.fly.dev # public origin (canonical, OG, sitemap, llms.txt); change when you attach a domainResuma OS (exec layer):
RESUMA_DATA_DIR=/data/resuma
RESUMA_EXEC_ENABLED=1 # mount exec routes without .workers()
RESUMA_EXEC_PUBLIC=1 # dev only — open exec routes
RESUMA_METRICS_PUBLIC=0 # set 1 only inside VPC
RESUMA_SCHEDULER_TICK_SECS=30
RESUMA_WEBHOOK_SECRET=... # HMAC for outbound webhooksCheck your setup
resuma doctorReports RESUMA_ENV status and project health. See also Configure security (Rust SecurityConfig), Exec security, and Deploy.