Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

Rustybin is configured through environment variables; the only command-line option of the server is --config <file>, the rustybin.yaml declaring OpenAPI mocks. Invalid values never stop the server: they are logged as warnings and the default is used. Values are trimmed, and an empty value counts as unset (except for RUSTYBIN_CORS_ORIGINS, see below). Booleans accept 1, true, yes, on and 0, false, no, off (case-insensitive).

GET /_rustybin/config returns the effective configuration without secrets (the admin token is only reported as admin_token_configured).

This list is checked against src/config.rs and every std::env::var call in src/ (the MCP, mock LLM and A2A modules read a few variables of their own).

Listeners and process

VariableDefaultDescription
RUSTYBIN_HTTP_PORT80HTTP port. Failing to bind it is fatal (exit code 1). 0 picks a free port.
RUSTYBIN_HTTPS_PORT443HTTPS port (same routes as HTTP). Optional: a bind or certificate failure only logs a warning.
RUSTYBIN_GRPC_PORT50051gRPC port (EchoService, health, reflection, gRPC-Web). Optional, like HTTPS.
RUSTYBIN_HOST0.0.0.0Bind address for all listeners: an IPv4 or IPv6 address (::, [::]) or localhost (127.0.0.1).
RUSTYBIN_LOG_LEVELinfoLog filter in tracing EnvFilter syntax (debug, warn, rustybin=debug,tower_http=info, ...). Falls back to RUST_LOG; an unparsable filter means info. Logs go to stdout, coloured only when stdout is a terminal.
RUSTYBIN_LOG_FORMATtexttext or json (one JSON object per line, with the request's method, path and request_id in a span object). json by default in hosted mode. See Logs.
RUSTYBIN_GRPC_ON_HTTPfalseAlso serve the gRPC services on the HTTP and HTTPS listeners for requests with content-type: application/grpc* (HTTP/2; the HTTPS listener then offers h2 through ALPN), so a TLS-terminating proxy can forward gRPC on 443. See gRPC.
RUSTYBIN_INSTANCE_IDrandom UUIDInstance name returned by /identity, /health, the mock LLM (X-Rustybin-Instance) and the gRPC EchoService. Set it per replica for load balancing demos.
RUSTYBIN_REQUEST_TIMEOUT120Seconds until the response headers must be ready, else 503. Streaming bodies (SSE, WebSocket, slow drips) are not cut once headers are sent. 0 disables the timeout.
RUSTYBIN_BODY_LIMIT1048576Maximum request body in bytes; larger bodies get 413. Also the size up to which /echo shows a body.

The process stops gracefully on SIGTERM or SIGINT: listeners stop accepting and in-flight connections (streams included) get 10 seconds to finish. GET /_rustybin/ready is the readiness probe (always 200 while serving); GET / the liveness check. The Docker image runs as an unprivileged user and supports a read-only root filesystem, see Containers.

Proxies and TLS

VariableDefaultDescription
RUSTYBIN_TRUST_FORWARDfalseTrust proxy headers. Client IP: Fly-Client-IP, then RFC 7239 Forwarded: for=, X-Forwarded-For (the rightmost address that is not private or loopback, so clients cannot spoof it by prepending), then X-Real-IP. Scheme, host and port: X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-Port and Forwarded: proto= host=. The OIDC issuer also honours X-Forwarded-Prefix. Enable it only behind a proxy you control.
RUSTYBIN_TLS_CERTcerts/server.crtCertificate of the HTTPS listener (relative to the working directory).
RUSTYBIN_TLS_KEYcerts/server.keyPrivate key of the HTTPS listener.
RUSTYBIN_MTLS_IN_HEADERunsetName of a request header in which a gateway that terminated mTLS forwards the client certificate (URL-encoded PEM, raw PEM or base64 DER). /auth/mtls then verifies it against the demo CA. See Authentication.

Demo PKI. At startup Rustybin loads a demo CA from ca.crt and ca.key in the directory of RUSTYBIN_TLS_CERT, or generates one and writes it there (best effort), so client certificates issued before a restart stay valid. Rustybin only reuses or replaces files it created (a CA certificate with the subject CN=Rustybin Demo CA): if ca.crt / ca.key hold another CA, such as your own, they are left untouched with a warning and the demo CA lives in rustybin-demo-ca.crt / rustybin-demo-ca.key instead (if those names are taken by something else too, it is kept in memory only). For the HTTPS listener:

  • if both RUSTYBIN_TLS_CERT and RUSTYBIN_TLS_KEY exist, they are used (a stale pair issued by an older demo CA is replaced; a key that does not match the certificate is an error and HTTPS does not start);
  • if neither exists, a server certificate for localhost, 127.0.0.1, ::1 and rustybin signed by the demo CA is generated and written there;
  • if only one exists, nothing is written and the generated pair is used in memory.

Download the CA and a client certificate from /auth/mtls/get-ca-cert and /auth/mtls/get-client-cert. The HTTPS listener asks for a client certificate but does not require one; when one is presented it must chain to the demo CA.

Shared instances

VariableDefaultDescription
RUSTYBIN_PUBLIC_MODEfalseHardening for shared, internet-facing instances: lower caps everywhere, the inspector only captures requests tagged with X-Rustybin-Session, and instance-global mutations are refused unless an admin token is configured. See Sessions, public mode and the admin token.
RUSTYBIN_ADMIN_TOKENunsetWhen set, instance-global mutations (health toggles, POST /flaky/reset?scope=all, clearing every captured request) need Authorization: Bearer <token> or X-Rustybin-Admin-Token: <token> (or a control-plane JWT with the admin scope). With RUSTYBIN_CONTROL_AUTH=token or jwt it also opens the whole control plane. Never returned by any endpoint.
RUSTYBIN_CORS_ORIGINS*Allowed CORS origins, comma separated. off or an empty value removes the CORS layer entirely, so a gateway's own CORS plugin can be demonstrated.
RUSTYBIN_INSPECTOR_CAPACITY500Requests kept by the request inspector ring buffer (1 to 10000).

Control plane and console

See Control-plane security, metrics and operations.

VariableDefaultDescription
RUSTYBIN_CONTROL_AUTHopenopen: /_rustybin/* needs no credentials. token: every /_rustybin/* route except /_rustybin/ready needs RUSTYBIN_ADMIN_TOKEN. jwt: the admin token or an Ed25519 JWT signed by RUSTYBIN_CONTROL_JWT_PUBLIC_KEY (scopes inspector, console, admin). Data-plane routes and the console's static files are never affected. jwt by default in hosted mode.
RUSTYBIN_CONTROL_JWT_PUBLIC_KEYunsetEd25519 public key for control-plane JWTs: PEM (newlines may be \n), base64 DER, or base64 / base64url of the raw 32 bytes. Invalid: warning, JWTs refused.
RUSTYBIN_CONTROL_JWT_AUDIENCERUSTYBIN_INSTANCE_IDRequired aud claim of control-plane JWTs.
RUSTYBIN_HOSTED_MODEfalsePreset for platforms running one instance per customer: control auth jwt and JSON logs, unless RUSTYBIN_CONTROL_AUTH / RUSTYBIN_LOG_FORMAT say otherwise.
RUSTYBIN_CONSOLE_TITLEunsetShown in the console header and tab title (control characters removed, at most 80 characters).
RUSTYBIN_CONSOLE_BACKLINKunsethttp:// or https:// URL shown as a "Back to ..." link in the console header and sign-in screen; anything else is ignored with a warning.

OpenAPI mocks

See Configuration as code.

VariableDefaultDescription
RUSTYBIN_CONFIG_FILE./rustybin.yaml if it existsA rustybin.yaml declaring OpenAPI mocks, loaded at startup and reloaded by SIGHUP or POST /_rustybin/mocks/reload. The command-line option --config <file> takes precedence. Problems are logged and listed in GET /_rustybin/mocks (load_errors); they never stop the server.
RUSTYBIN_MOCKS_DIRunsetA directory whose *.yaml, *.yml and *.json OpenAPI files (up to 200) each become a mock named after the file, with default settings.
RUSTYBIN_MOCKS_SAMPLEtrue (false in public mode)Create the built-in petstore mock.
RUSTYBIN_MOCKS_STATE_DIRunsetSave mocks created or edited through the API or console in this directory (one JSON file each, written on every change) and load them at startup. File-defined mocks are not saved. See Configuration as code.
RUSTYBIN_MOCKS_HOSTunsetDomain for host-based mock URLs, e.g. mock.example.com: a request to petstore.mock.example.com/v1/pets is served by the mock petstore. Needs wildcard DNS (and a wildcard certificate for HTTPS). See Configuration as code.

${VAR} and ${VAR:-default} in the config file are expanded from the environment (see Environment variables). The rustybin mock CLI reads RUSTYBIN_SERVER (default http://localhost on RUSTYBIN_HTTP_PORT, port 80 when unset) and RUSTYBIN_TOKEN (else RUSTYBIN_ADMIN_TOKEN) as defaults for --server and --token.

Plan limits

Off by default. See Plans and limits for the presets, the response headers and what is exempt.

VariableDefaultDescription
RUSTYBIN_PLANnonenone (nothing enforced, no extra header), free, pro, team or enterprise (no limits, plan name reported).
RUSTYBIN_LIMIT_RPSplanSustained requests per second (token bucket refill rate).
RUSTYBIN_LIMIT_BURSTplanToken bucket capacity; 0 means the same as the rps value.
RUSTYBIN_LIMIT_CONCURRENCYplanRequests in flight at once (a response counts until its body is sent).
RUSTYBIN_LIMIT_STREAMSplanOpen SSE responses and WebSocket connections at once.
RUSTYBIN_LIMIT_STREAM_SECSplanMaximum stream lifetime in seconds; longer streams are ended cleanly.
RUSTYBIN_LIMIT_REQUESTSplanRequests per period.
RUSTYBIN_LIMIT_EGRESS_MBplanResponse body megabytes per period (1 MB = 1,000,000 bytes, fractions such as 0.5 allowed).
RUSTYBIN_LIMIT_PERIODplanQuota period: day or month (calendar UTC).
RUSTYBIN_LIMIT_SCOPEplaninstance (one set of counters) or session (one set per X-Rustybin-Session, else client IP).
RUSTYBIN_USAGE_FILEunsetPath of a JSON file holding the instance quota counters, written every 30 s and on graceful shutdown and read at startup, so a restart cannot reset a monthly quota. Session counters are never persisted.

Every RUSTYBIN_LIMIT_* value accepts 0 or unlimited to turn that dimension off. Setting any of them without a plan enables the limiter with the plan name custom.

API keys and shared mode

Off by default. See Shared mode and API keys for the registry format, quotas, scoping and the control plane.

VariableDefaultDescription
RUSTYBIN_SHARED_MODEfalseOne instance for many API keys: every data-plane request needs a key (X-Rustybin-Key, else ?rb_key=), each key has its own limits and daily quotas, inspector and usage are scoped by key, the rest of the control plane needs the admin token. Implies RUSTYBIN_PUBLIC_MODE, RUSTYBIN_LIMIT_SCOPE=session and RUSTYBIN_LIMIT_PERIOD=day.
RUSTYBIN_REQUIRE_KEYfalseOn a normal instance: the data plane needs a valid key from the registry; no per-key limits, control-plane auth unchanged.
RUSTYBIN_KEYS_FILEunsetKey registry file (JSON), read at startup and reloaded when it changes (checked every 5 s). Wins over RUSTYBIN_KEYS_URL.
RUSTYBIN_KEYS_URLunsetKey registry URL (http:// or https://), fetched at startup and every RUSTYBIN_KEYS_POLL_SECS with If-None-Match. Errors keep the last good registry.
RUSTYBIN_KEYS_TOKENunsetSent to RUSTYBIN_KEYS_URL as Authorization: Bearer <token>. Never returned by any endpoint.
RUSTYBIN_KEYS_POLL_SECS30Registry URL poll interval in seconds (every 5 s at most while nothing was loaded yet).
RUSTYBIN_KEYS_MAX200000Most keys accepted in a registry; a larger registry is refused with a warning (the last good one stays).
RUSTYBIN_QUOTA_STOREunsetpostgres://... URL of a PostgreSQL database shared by the replicas for daily quotas (table key_usage, created when missing). Needs a binary built with --features quota-postgres; otherwise a warning and local counting. Never returned by any endpoint.
RUSTYBIN_QUOTA_STORE_CAunsetPEM file with extra CA certificates for the quota store's TLS (besides the public web roots).
RUSTYBIN_QUOTA_FLUSH_MS2000How often each replica flushes its counts to the quota store, in milliseconds.
RUSTYBIN_QUOTA_UPGRADE_URLunsethttp:// or https:// link returned as upgrade_url in daily quota 429 bodies (null when unset).

MCP server

Read when the server starts.

VariableDefaultDescription
RUSTYBIN_MCP_API_KEYunsetThe only X-API-Key value /mcp/apikey accepts. Unset: any non-empty key is accepted.
RUSTYBIN_MCP_ALLOWED_ORIGINS*Comma-separated Origin values accepted by every MCP endpoint (DNS rebinding protection). Requests with another Origin get 403; requests without Origin are always accepted.
RUSTYBIN_MCP_ACCEPTED_AUDIENCESrustybinToken audiences /mcp/protected accepts besides its own resource URL. The default is the identity provider's default audience, so a plain client_credentials token works. none accepts only tokens issued for the resource (strict RFC 8707).
RUSTYBIN_MCP_RESOURCE_URLderivedOverride the resource identifier of /mcp/protected (by default <scheme>://<host>/mcp/protected from the request). Set it to the gateway's public URL when the gateway does not forward Host.
RUSTYBIN_MCP_CLOCK_TICK_SECS5Update interval of the subscribable rustybin://clock resource (1 to 3600).

Mock LLM

VariableDefaultDescription
RUSTYBIN_AI_REQUIRE_AUTHfalseRequire each provider's native credential on every /ai/* call (per request: X-Rustybin-Require-Auth: true).
RUSTYBIN_AI_API_KEYunsetThe only accepted key (implies RUSTYBIN_AI_REQUIRE_AUTH). For Bedrock SigV4 it is compared with the access key id.

See Faults, latency, credentials, inspection.

A2A agents

VariableDefaultDescription
RUSTYBIN_A2A_PUSH_ALLOWLISTunsetComma-separated host or host:port entries that push notification URLs may point to. The built-in sink /a2a/webhook-sink/{id} on this server is always allowed.
RUSTYBIN_A2A_PUSH_ALLOW_ALLfalseAllow push notifications to any http(s) URL, including loopback and private addresses. Ignored in public mode.

Development only

VariableUsed by
RUSTYBIN_UPDATE_READMERUSTYBIN_UPDATE_README=1 cargo test readme_endpoints rewrites the endpoint tables in README.md.
RUSTYBIN_BIN, RUSTYBIN_DOCS_PORT, REQUIRE_ALL_TOOLSdocs/examples/run.sh (see How the examples work).
PYTHON, RUSTYBIN_CONFORMANCE_PORT, RUSTYBIN_URL, MCP_BASEThe SDK conformance scripts under conformance/.
RUSTYBIN_UI_PORT, RUSTYBIN_JWT_URL, CONTROL_JWT_PRIVATE_KEY, CONTROL_JWT_AUDIENCEconformance/ui/run.sh and console_e2e.py (the console check, including the sign-in flow).
RUSTYBIN_GIT_SHABuild time: the commit reported by /_rustybin/version and the metrics when the source tree has no .git (Docker builds: --build-arg RUSTYBIN_GIT_SHA=<commit>).

Limits that are not configurable

Request-reachable state is always bounded. The main caps (normal mode / public mode):

WhatNormalPublic
X-Rustybin-Delay, /drip duration and delay, JSON-RPC sleep, bin response delay30 s10 s
/delay/{duration}60 s10 s
/bytes, /stream-bytes, /range size100 KiB10 KiB
/stream/{n} lines10020
/drip bytes102401024
/sse events / interval / stream lifetime1000 / 60 s / 10 min100 / 10 s / 2 min
/sse/chat tokens / delay per token500 / 2 s200 / 1 s
JSON-RPC batch size10020
WebSocket message size / idle timeout / lifetime1 MiB / 5 min / 1 h256 KiB / 1 min / 10 min
Request bins (total / per session / requests per bin / bytes per bin / TTL)200 / 200 / 100 / 1 MiB / 24 h100 / 10 / 50 / 256 KiB / 1 h
Flaky counters (idle TTL 1 h)100002000
OAuth codes, refresh tokens, revocations / registered clients10000 / 10002000 / 200
Mock LLM request records (1 h TTL) / choices n / embedding dimensions1000 / 8 / 4096200 / 2 / 1536
MCP sessions (idle TTL) / long-lived streams1000 (30 min) / 1 h200 (10 min) / 5 min
A2A tasks (total / per session / idle TTL)5000 / 1000 / 1 h2000 / 50 / 15 min
OpenAPI mocks (mocks / spec size / operations / captured requests per mock / lifetime of API-created mocks)100 / 1 MiB / 500 / 200 / unlimited50 / 256 KiB / 200 / 50 / 24 h
Inspector entriesRUSTYBIN_INSPECTOR_CAPACITY (max 10000)same
Metrics series (route values / LLM token series)1024 / 256 (beyond: other)same