gateway.yaml is the configuration file for a self-hosted ManyLayers deployment. The gateway, workspace and deployer services all read the same file, passed with -config. Copy configs/gateway.example.yaml to gateway.yaml and edit it. The container image ships configs/gateway.container.yaml at /etc/manylayers/gateway.yaml as its default.
ManyLayers Cloud is configured through the console, not this file.
Interpolation.
${ENV_VAR} and ${ENV_VAR:-default} are expanded when the file loads. An unset variable becomes an empty string, so a key like upstream_api_key: ${OPENAI_API_KEY} with the variable missing is empty, and an empty team API key stops startup. HashiCorp Vault references also work: ${vault:secret/data/path#key} (requires VAULT_ADDR and VAULT_TOKEN); one that cannot be resolved fails startup.GATEWAY_PORT (server.listen), DATABASE_URL (database.url), REDIS_URL (redis.url), SHUTDOWN_TIMEOUT (server.shutdown_timeout), MANYLAYERS_ENCRYPTION_KEY (connectors.encryption_key) and MANYLAYERS_PII_VAULT_KEYS / MANYLAYERS_PII_VAULT_KEY_VERSION (pii.vault). See Self-hosting for the full list.
server
listen applies to the gateway only. A request over max_body_bytes is refused with 413 body_too_large. Changes to this section require a restart.
database
url is empty it defaults to postgres://postgres:test@localhost:5532/manylayers?sslmode=disable, the local dev stack.
The long-running services do not migrate the schema. Run dbtool migrate -config <file> (the compose migrate job) before first start and before every upgrade; a service whose schema is behind refuses to start. Changes to this section require a restart.
redis
auth
ml- is verified against the issuer. audience is required once issuer is set, and audience or jwks_url without issuer is an error.
audit
GET /admin/audit/verify, which checks the most recent 10,000 records. See Request Logging & Audit.
pii
builtin detector uses regex-based entity recognition (email, phone, SSN, credit card and similar). The http detector calls a Presidio-style sidecar at http_url. With vault.keys set, each redacted value becomes a numbered token and is stored encrypted beside the trace, so authorized administrators can reveal it. current_key may be omitted when exactly one key is configured. See PII redaction.
firewall
audit mode, detections are recorded but not blocked. In enforce mode, a request over the threshold is refused with 403 prompt_injection. A team can override the default with its own firewall_mode. See Prompt injection.
cache
store: qdrant shares the semantic cache across replicas and requires rag.qdrant.url. A request is cached only when the cache is enabled here, caching is enabled for its team (cache_enabled), and the request has temperature: 0 or the model sets cache: true. See Caching.
async
/v1/async/*. See Async requests.
queue
db backend uses Postgres and needs no extra infrastructure. The kafka backend uses consumer groups with at-least-once delivery: a message that fails 5 times is published to <topic>.dlq. Changes to this section require a restart.
router
rag
/v1/kb). The memory store is per process and lost on restart; use qdrant for anything persistent.
connectors
MANYLAYERS_ENCRYPTION_KEY overrides this value. When neither is set, each service generates a key in data/credentials.key (or MANYLAYERS_ENCRYPTION_KEY_FILE); with more than one service or replica, set the key explicitly so they can all read each other’s credentials. Changing the key makes existing sealed credentials unreadable.
suite
/auth/*) and the /w/* endpoints for chat, agents, workflows, evals and knowledge bases. Leave it false and the Workspace service serves neither. public_url is your own console address; if empty, invitation links use the origin the inviting administrator was on.
deployer
telemetry
Other sections
billing (billing webhooks and the on-prem license file), saas (signup_approval_required), notifications.slack and staff (Staff Portal session length) configure operator features of the control plane. The mode: key is accepted and ignored. See Deployment Model.
models
Each entry maps a logical name (what clients send) to one or more upstreams (where requests go):| Field | Notes |
|---|---|
logical_name | Required and unique. |
provider | One of openai (default), anthropic, azure, gemini, vertex, bedrock, cohere, typesafe, mistral, groq, deepseek, together, perplexity, xai, fireworks, openrouter, cerebras, sambanova, ai21, ollama. |
upstream_url, upstream_model, upstream_api_key | Single-endpoint form. Use either these or upstreams, not both. For the OpenAI-compatible presets (mistral, groq, deepseek, together, perplexity, xai, fireworks, openrouter, cerebras, sambanova, ai21, ollama) upstream_url can be omitted and defaults to the provider’s public endpoint (ollama defaults to http://localhost:11434). |
upstreams | List of endpoints for failover and load balancing: url, model, api_key, weight (default 1), provider, api_version (Azure, default 2024-06-01), region (AWS). |
aws_region | Required for bedrock. The key is ACCESS_KEY:SECRET_KEY[:SESSION_TOKEN], or a Bedrock API key. |
aliases | Extra names that resolve to this model. |
cached_input_price_per_1k, cache_write_price_per_1k | Prices for cached and cache-write prompt tokens. Unset means billed at input_price_per_1k. |
media_prices | image (per image), speech_per_1k_chars, transcription (per request). |
cache | true caches responses even when temperature is not 0. |
pii_output_mode | buffer scans and redacts the completion before it is returned, which delays streaming. |
bedrock_mantle, sagemaker or databricks) cannot be declared in gateway.yaml.
aliases
A model may declare additional names that resolve to it. Aliases let callers keep sending a name they already use while you change what serves it:GET /v1/models, work on GET /v1/models/{model}, and a team policy naming either the alias or the model grants both. A model name always wins over an alias of the same name, so an alias can never reroute traffic away from a real model.
See Providers for per-provider configuration and OpenAI Compatibility for what each provider can honor.
teams
Seeds teams, their limits and API keys:POST /admin/keys or the console’s API Keys page to set them. Every name in models must be a logical_name defined above (or *).
Send SIGHUP to a running service to reload models and teams without downtime. Other sections are read at startup. Sections that the console’s Settings page manages are seeded from this file on first boot and then owned by the database; see Settings & Configuration Precedence.