Console
Sign in
Docs for Platform operator
On this page
  1. Files
  2. Route-level overrides
  3. Required in production
  4. Credentials
  5. Listener and route table
  6. Identity provider
  7. Access
  8. Sessions and identity signing
  9. Shared state
  10. Upstream TLS
  11. Browser and network
  12. TLS of the deployment
  13. Limits
  14. WebSockets
  15. Operations
  16. Control plane
  17. Test suite

Configuration

Every GATEWAY_* environment variable the gateway and its control plane read, with defaults and production requirements, and the files they read. It is for operators; the rules the gateway applies to its environment are in spec §4.

Read byPlatform operatorSecurity engineerDatabase administrator

"Production" means NODE_ENV=production. Durations are in milliseconds unless the name says otherwise; for limits, 0 disables the limit. .env.example holds the same list as a starting file. A value that cannot be parsed stops the gateway at startup.

Files#

FileRead bySet withFormat
Route tablegatewayGATEWAY_CONFIG (default ./config/routes.json), when GATEWAY_CONFIG_SOURCE=file, and as the fallback of an empty storeJSON, spec §3. Watched; a reload is atomic (spec §12.3).
Control-plane token mapgateway-controlGATEWAY_CONTROL_TOKENS_FILEJSON {token: {operator, scope}} (spec §12.7).
.envyour process manager—Copy of .env.example, adjusted. Keep credentials out of it: they belong in the platform's secret store.
deploy/redis/gateway.aclthe Redis server, not the gatewaythe server's aclfileOne ACL rule per line (Operations: roles).

Route-level overrides#

These route-table keys override an environment default for one route (spec §3.1):

KeyDefaultOverridesUse it to
maxBodyBytesdefaults.maxBodyBytesGATEWAY_MAX_BODY_BYTESRaise or lower the body limit of one route.
crossSitenavigationGATEWAY_CSRF_STRICTSet strict when the upstream changes state on a GET.
forwardAuthorizationfalse—Set true when the upstream needs the caller's token.
accessCacheTtlMsenvironmentGATEWAY_ACCESS_CACHE_TTL_MSSet 0 for immediate revocation.
accessStaleGraceMsenvironmentGATEWAY_ACCESS_STALE_GRACE_MSServe the last allow decision during an Access outage.
replayMaxBytesenvironmentGATEWAY_REPLAY_MAX_BYTESCap bodies resent to the next upstream.
timeouts.upstreamAttemptMsenvironmentGATEWAY_UPSTREAM_ATTEMPT_TIMEOUT_MSBudget one attempt across several upstreams; 0 disables it.
upstreamHostaddress—Set original when the upstream answers under a public name: an issuer of tokens, a console.

Two keys of the table are not route-level:

KeyMeaning
version1 or 2. Version 2 adds hosts and upstreamHost.
hostsThe names the gateway serves itself on. Empty means every name: the gateway is the only service of the deployment. A list means the gateway is the front door of a platform, and the endpoints it serves itself belong to those names (spec §2.2).

Required in production#

The gateway refuses to start in production without these; the error names the missing variable. Why each one is required: spec §4.3.

VariableEscape hatch
GATEWAY_SESSION_SECRET—
GATEWAY_IDENTITY_SIGNING_KEY (or GATEWAY_IDENTITY_SIGNING_KEY_BASE64)—
GATEWAY_OIDC_ISSUER, GATEWAY_OIDC_CLIENT_ID, GATEWAY_OIDC_REDIRECT_URI—
GATEWAY_OIDC_CLIENT_SECRETGATEWAY_OIDC_ALLOW_PUBLIC_CLIENT=true
GATEWAY_ACCESS_URL—
GATEWAY_ACCESS_TOKENGATEWAY_ACCESS_ALLOW_ANONYMOUS=true
One of GATEWAY_RATE_LIMIT_MAX, GATEWAY_RATE_LIMIT_GLOBAL_MAX, GATEWAY_RATE_LIMIT_PRINCIPAL_MAX, GATEWAY_RATE_LIMIT_TOTAL_MAX above 0GATEWAY_ALLOW_NO_RATE_LIMITS=true
GATEWAY_SESSION_URL and GATEWAY_SHARED_STATE_URL naming a Redis or Postgres serverGATEWAY_ALLOW_MEMORY_STATE=true

gateway-control always requires GATEWAY_CONTROL_STATE_URL.

Credentials#

In production the gateway refuses to start when a credential is short, is one repeated character, or is a value the repository publishes (spec §4.3). The rule covers GATEWAY_SESSION_SECRET, GATEWAY_ACCESS_TOKEN, GATEWAY_OIDC_CLIENT_SECRET and GATEWAY_METRICS_TOKEN.

VariableRule in production
GATEWAY_SESSION_SECRETAt least 32 bytes, counted as decoded (64 hexadecimal characters, 44 base64 characters).
GATEWAY_ACCESS_TOKENAt least 32 bytes, counted as decoded.
GATEWAY_OIDC_CLIENT_SECRETAt least 32 bytes, counted as decoded.
GATEWAY_METRICS_TOKENAt least 32 bytes, counted as decoded.

The values of .env.min, of the examples and of the fixtures are published: the gateway refuses them, and so does the control plane with the token of the map of the example.

Listener and route table#

VariableDefaultEffect
GATEWAY_HOST0.0.0.0Listen address.
GATEWAY_PORT8080Listen port.
GATEWAY_CONFIG./config/routes.jsonRoute table file.
GATEWAY_CONFIG_SOURCEfilefile: watch GATEWAY_CONFIG. store: read revisions the control plane writes to the shared state (spec §3.4).
GATEWAY_EXTERNAL_PROTOhttpProtocol clients use to reach the gateway (http or https).

Identity provider#

VariableDefaultEffect
GATEWAY_OIDC_ISSUER—Provider issuer URL. Required in production.
GATEWAY_OIDC_CLIENT_IDgatewayClient ID. Required in production.
GATEWAY_OIDC_CLIENT_SECRET—Client secret. Required in production unless public client.
GATEWAY_OIDC_REDIRECT_URI—Callback URL, for example http://localhost:8080/auth/callback; the URL the gateway is reached under. Required in production.
GATEWAY_OIDC_SCOPESopenid,profile,email,groupsRequested scopes, comma-separated.
GATEWAY_OIDC_ROLES_CLAIMrolesClaim that carries roles.
GATEWAY_OIDC_AUDIENCEthe client IDAudience a bearer token must carry.
GATEWAY_OIDC_REQUIRED_TOKEN_CLAIMS—Comma-separated claims a bearer token must carry, for a provider with a token-type claim (for example scp).
GATEWAY_OIDC_REJECT_NONCE_TOKENtrueRefuse a bearer token that carries a nonce (an ID token). Turn off only for a provider whose access tokens carry one.
GATEWAY_OIDC_MAX_TOKEN_AGE_MS86400000Longest bearer-token lifetime (issue to expiry). 0 turns the bound off; an expiry is required either way (spec §5.4).
GATEWAY_OIDC_ALLOW_INSECUREtrue outside productionAccept a provider not served over https.
GATEWAY_OIDC_ALLOW_PUBLIC_CLIENTfalseAccept a provider client without a secret.

Access#

VariableDefaultEffect
GATEWAY_ACCESS_URL—Base URL, for example http://access.internal:8090. Required in production.
GATEWAY_ACCESS_TOKEN—Token the gateway authenticates with. Required in production unless anonymous.
GATEWAY_ACCESS_ALLOW_ANONYMOUSfalseAccess authenticates the gateway by other means.
GATEWAY_ACCESS_TIMEOUT_MS3000Wait for a decision. Minimum 1.
GATEWAY_ACCESS_CACHE_TTL_MS5000Decision cache lifetime, which is the revocation latency. Routes override it with accessCacheTtlMs.
GATEWAY_ACCESS_STALE_GRACE_MS0Serve the last allow decision this long into an outage (spec §6.2). Routes override it with accessStaleGraceMs. Max 3600000.
GATEWAY_ACCESS_BREAKER_FAILURES5Consecutive failures before Access is no longer called. 0 disables the breaker (spec §6.4).
GATEWAY_ACCESS_BREAKER_COOLDOWN_MS5000How long the open breaker skips Access. Max 3600000.

Sessions and identity signing#

VariableDefaultEffect
GATEWAY_SESSION_URLmemory://localSession store. The scheme picks the backend: memory://, redis://, rediss://, postgres://, postgresql:// (URL forms).
GATEWAY_SESSION_KEY_PREFIXgatewayPrefix of every key, so environments can share a server.
GATEWAY_SESSION_SECRET—Signs the login state cookie. Same value on every replica. Required in production; unset, each process generates its own.
GATEWAY_IDENTITY_SIGNING_KEY—PEM P-256 private key that signs request identities. Same key on every replica. Required in production; without it, a non-production process signs with a key it generates, which no upstream can verify. bun run identity:key generates a pair.
GATEWAY_IDENTITY_SIGNING_KEY_BASE64—The same key in base64, for secret stores that hand out base64.
GATEWAY_SESSION_TTL_MS28800000Idle lifetime. Minimum 1000.
GATEWAY_SESSION_MAX_AGE_MS86400000Maximum age from creation. 0 means none.
GATEWAY_SESSION_TOUCH_INTERVAL_MS60000A session is rewritten at most once per interval.
GATEWAY_SESSION_MAX_SESSIONS5000Capacity of the in-process store.
GATEWAY_SESSION_TLS_CA, GATEWAY_SESSION_TLS_CA_BASE64—CA of a private session-store endpoint (PEM or base64).

Shared state#

VariableDefaultEffect
GATEWAY_SHARED_STATE_URLthe session URL, when that names a shared serverServer for rate-limit windows and cached decisions. Required in production.
GATEWAY_SHARED_STATE_KEY_PREFIXgatewayKey prefix.
GATEWAY_SHARED_STATE_TLS_CA, GATEWAY_SHARED_STATE_TLS_CA_BASE64—CA of a private endpoint.
GATEWAY_REDIS_SENTINEL_MASTER—Master name the sentinels agree on, when the URL hosts are Redis sentinels. Leave it unset when not behind Sentinel.
GATEWAY_ALLOW_MEMORY_STATEfalseAllow in-process state in production, for a single node that accepts losing sessions with the process.

The URL selects the server type of GATEWAY_SESSION_URL and GATEWAY_SHARED_STATE_URL; GATEWAY_CONTROL_STATE_URL names one of the same servers:

URLServer
memory://localIn-process store, for a single node only.
redis://host:6379/0Redis server.
rediss://host:6379/0Redis server with transport encryption.
redis://host-a:6379,host-b:6379/0Redis cluster; the hosts are its masters.
redis://host-a:26379,host-b:26379/0 with GATEWAY_REDIS_SENTINEL_MASTERRedis Sentinel; master and replicas are discovered from the sentinels.
postgres://user:password@host:5432/gatewayPostgres server.
postgresql://user:password@host:5432/gatewaySame Postgres server.

Postgres only (no effect on Redis):

VariableDefaultEffect
GATEWAY_POSTGRES_POOL_MAX10Connections per replica (1–1000).
GATEWAY_POSTGRES_CONNECTION_TIMEOUT_MS5000Wait for a pool connection. Minimum 100.
GATEWAY_POSTGRES_STATEMENT_TIMEOUT_MS5000Longest statement. Minimum 100.
GATEWAY_POSTGRES_SYNCHRONOUS_COMMIToffon makes the server wait for the disk (spec §12.5).
GATEWAY_POSTGRES_AUTO_MIGRATEtrue outside productionBuild the schema on connect. Set false when you run bun run postgres:migrate yourself.

Upstream TLS#

VariableDefaultEffect
GATEWAY_UPSTREAM_TLS_CA, GATEWAY_UPSTREAM_TLS_CA_BASE64—CA that signs upstream certificates.
GATEWAY_UPSTREAM_TLS_CERT, GATEWAY_UPSTREAM_TLS_CERT_BASE64—Client certificate presented to upstreams that ask.
GATEWAY_UPSTREAM_TLS_KEY, GATEWAY_UPSTREAM_TLS_KEY_BASE64—Its private key. Setting the certificate without the key, or the reverse, stops startup.

WebSocket upstreams always use plain http (spec §11.1.2).

Browser and network#

VariableDefaultEffect
GATEWAY_COOKIE_SECUREtrue in productionSecure attribute on cookies.
GATEWAY_ALLOWED_ORIGINS—Origins allowed besides the gateway's own, comma-separated.
GATEWAY_CSRF_STRICTfalseAlso refuse cross-site navigations. Routes opt in with crossSite: "strict" (spec §8).
GATEWAY_TRUSTED_PROXIES—CIDR ranges whose forwarding headers are trusted, comma-separated. When set, replaces the file's trustedProxies. A range of a production deployment covers at most sixteen addresses (spec §7.3).
GATEWAY_TRUSTED_PROXY_HOPS1Number of trusted proxies in front (1–16) (spec §7.3).

TLS of the deployment#

The gateway terminates the TLS of the callers when it has a certificate of the deployment (spec §11.5).

| GATEWAY_TLS_NAMES | — | The names the certificate covers, comma-separated. An empty list means the gateway does not terminate TLS: the proxy in front of it does. | | GATEWAY_TLS_PORT | 443 | The port of the listener of TLS. Zero is a port the machine draws. | | GATEWAY_TLS_CERT_FILE | — | The file of a certificate the deployment manages itself, in PEM. | | GATEWAY_TLS_KEY_FILE | — | The file of the private key of that certificate, in PEM. | | GATEWAY_ACME_DIRECTORY | https://acme-v02.api.letsencrypt.org/directory | The directory of the authority of the certificates. | | GATEWAY_ACME_EMAIL | — | The contact of the account of the deployment. | | GATEWAY_ACME_ACCOUNT_KEY | — | The key of the account of the deployment, in PEM. It is a secret of the deployment: the replicas share the account and the budget of the authority. | | GATEWAY_ACME_CHALLENGE | http-01 | The challenge the deployment answers: http-01 or dns-01. | | GATEWAY_ACME_DNS_HOOK_URL | — | The writer of the records of DNS, for the dns-01 challenge. | | GATEWAY_TLS_RENEWAL_DAYS | 30 | The number of days before the expiry that the certificate is renewed. |

The responder of the challenges of the authority is a process of its own (gateway-challenges, spec §11.5). It answers the challenges on the plain HTTP of the deployment, and it reads them from the shared state.

| GATEWAY_CHALLENGE_HOST | 0.0.0.0 | The address the responder binds to. | | GATEWAY_CHALLENGE_PORT | 80 | The port the responder listens on. | | GATEWAY_CHALLENGE_STATE_URL | — | The address of the shared state of the deployment. | | GATEWAY_CHALLENGE_STATE_KEY_PREFIX | gateway | The prefix of the keys of the shared state. |

Limits#

VariableDefaultEffect
GATEWAY_RATE_LIMIT_MAX, GATEWAY_RATE_LIMIT_WINDOW_MS0, 60000One caller on one route.
GATEWAY_RATE_LIMIT_GLOBAL_MAX, GATEWAY_RATE_LIMIT_GLOBAL_WINDOW_MS0, 60000One caller across all routes.
GATEWAY_RATE_LIMIT_PRINCIPAL_MAX, GATEWAY_RATE_LIMIT_PRINCIPAL_WINDOW_MS0, 60000One authenticated subject on one route.
GATEWAY_RATE_LIMIT_TOTAL_MAX, GATEWAY_RATE_LIMIT_TOTAL_WINDOW_MS0, 1000The whole deployment; the only scope that bounds a flood from many addresses.
GATEWAY_LOGIN_RATE_LIMIT_MAX, GATEWAY_LOGIN_RATE_LIMIT_WINDOW_MS30, 60000Login attempts per caller.
GATEWAY_RATE_LIMIT_FALLBACKlocalWhile the shared state is unreachable: local counts per process, open allows all, closed refuses all (spec §9).
GATEWAY_ALLOW_NO_RATE_LIMITSfalseAllow production with every rate limit off.
GATEWAY_MAX_BODY_BYTES10485760Default request body limit.
GATEWAY_MAX_CONCURRENT_REQUESTS1000Concurrent upstream exchanges.
GATEWAY_MAX_PENDING_REQUESTS1000Requests inside the gateway, including those waiting on Access. Overflow gets 503 gateway_overloaded (spec §2.4).
GATEWAY_UPSTREAM_ATTEMPT_TIMEOUT_MS2000Budget of one attempt when a route has several upstreams; resendable requests only. 0 disables it. Routes override it with timeouts.upstreamAttemptMs.
GATEWAY_REPLAY_MAX_BYTES65536Largest body held in memory so it can be resent to the next upstream. 0 streams every body. Routes override it with replayMaxBytes.
GATEWAY_UPSTREAM_BREAKER_FAILURES3Consecutive failures before an upstream moves to the end of the list (spec §11.4). 0 disables the breaker.
GATEWAY_UPSTREAM_BREAKER_COOLDOWN_MS30000How long it stays there.

Rate-limit windows have a minimum of 1000 ms, except GATEWAY_RATE_LIMIT_TOTAL_WINDOW_MS (minimum 100).

WebSockets#

VariableDefaultEffect
GATEWAY_WS_MAX_CONNECTIONS1000Open connections per replica.
GATEWAY_WS_MAX_PAYLOAD_BYTES16777216Largest message.
GATEWAY_WS_MAX_BUFFERED_BYTES262144Outbound buffer, in bytes.
GATEWAY_WS_MAX_BUFFERED_MESSAGES100Outbound buffer, in messages.
GATEWAY_WS_BACKPRESSURE_LIMIT_BYTES1048576Backlog at which a client that does not read is closed.
GATEWAY_WS_PING_INTERVAL_MS30000Keepalive ping interval.
GATEWAY_WS_PONG_TIMEOUT_MS90000Wait for a pong.
GATEWAY_WS_IDLE_TIMEOUT_SECONDS120Idle connection lifetime, in seconds.
GATEWAY_WS_HANDSHAKE_TIMEOUT_MS10000Budget of the upstream handshake. Minimum 100.
GATEWAY_WS_REVALIDATE_INTERVAL_MS60000Revalidation interval; 0 disables it.

Revalidation closes a connection whose session expired, access was revoked or route changed, with code 1008 (spec §10).

Operations#

VariableDefaultEffect
GATEWAY_METRICS_TOKEN—Bearer token for /metrics. Unset, the endpoint answers 404.
GATEWAY_SHUTDOWN_TIMEOUT_MS15000Drain deadline on SIGTERM and SIGINT.
GATEWAY_LOG_LEVELinfodebug, info, warn, error or silent.

Control plane#

Read by gateway-control only (spec §12.7).

VariableDefaultEffect
GATEWAY_CONTROL_HOST127.0.0.1Listen address.
GATEWAY_CONTROL_PORT9090Listen port.
GATEWAY_CONTROL_TOKENS_FILE—File holding the token map {token: {operator, scope}}. Scopes: read, operate, config. Tokens are at least 16 characters.
GATEWAY_CONTROL_TOKENS—The map inline. Prefer the file: the map is a secret.
GATEWAY_CONTROL_STATE_URL— (required)Shared state, with the control plane's credentials.
GATEWAY_CONTROL_STATE_TLS_CA, GATEWAY_CONTROL_STATE_TLS_CA_BASE64—CA of a private endpoint.
GATEWAY_CONTROL_KEY_PREFIXgatewayMust match the gateway's GATEWAY_SESSION_KEY_PREFIX.
GATEWAY_CONTROL_SHARED_STATE_KEY_PREFIXgatewayMust match the gateway's GATEWAY_SHARED_STATE_KEY_PREFIX.
GATEWAY_PROTECTED_ROUTES—Route IDs a table write may not remove or change, comma-separated.

The control plane also reads GATEWAY_MAX_BODY_BYTES, GATEWAY_UPSTREAM_ATTEMPT_TIMEOUT_MS, GATEWAY_REPLAY_MAX_BYTES, GATEWAY_ACCESS_STALE_GRACE_MS and GATEWAY_TRUSTED_PROXIES, with the same defaults: it compiles the tables it validates with them. Give it the gateway's values.

Test suite#

Read by tests, not the gateway: GATEWAY_TEST_REDIS_URL, GATEWAY_TEST_POSTGRES_URL, the GATEWAY_TEST_DEX_* variables of the interop tests, and the GATEWAY_TEST_ACCESS_* variables of the Access conformance suite (see Operations).