Skip to main content
Version: 5.x

Environment variables

MTE Relay Server (MRS) and MTE API Relay (MAR) run the same relay program and read the same settings. The two images differ in the MTE library build they link (see MRS and MAR images), not in configuration.

Every setting is an environment variable. When a relay is managed by the control plane, the control plane can override any setting in the group tables below, and each worker resolves a value in this order:

control plane override > environment variable > built in default

The Applies column says when a change takes effect:

  • live: a control plane change reaches every worker within one poll interval, with no restart. Six settings are live: DOMAIN_MAP, LOG_LEVEL, MAX_REQUEST_BODY_MIB, MAX_CONTROL_BODY_MIB, FORWARD_HEADERS, and HEALTH_CHECK_PATH.
  • restart: the worker reads the value when it builds its runtime. A control plane change is stored at once and applied the next time each worker starts.

A changed environment variable always needs a restart, because a process reads its environment when it starts.

How values are parsed​

Every setting the relay shares with SocketX has the same name, default, and parsing rule in both products.

  • Booleans accept true, 1, yes, on, false, 0, no, and off, in any letter case.
  • An empty value in the environment is the same as an unset one: the default applies and nothing is logged.
  • A value that does not parse as its type (a boolean, an integer, a level name) logs a warning that names the variable and the value in use, and the default applies: RATE_LIMITS "maybe" is not a boolean; using true, or LOG_LEVEL "verbose" is not a level name; logging at info. Such a value never fails startup. Under a control plane the warning is logged once per applied configuration version.
  • A few rules do fail startup: a LISTEN_PORT or PORT that is not a port number from 1 to 65535, a KYBER_STRENGTH outside 512, 768, and 1024, a DOMAIN_MAP that is not valid JSON, a TRUSTED_PROXIES entry that is not a usable IP address or CIDR, an invalid PROBE_PORT or PROBE_ADDR, and the bounds under Validation rules. A relay without a control plane exits with the reason.
  • PORT and MAX_PAIR_MIB are aliases kept so 4.x files keep working. The canonical name wins when both are set, and a disagreement is logged once: LISTEN_PORT 8080 and PORT 9000 disagree; using LISTEN_PORT.
  • HOSTNAME is retired. It never bound anything in 4.x or 5.x; LISTEN_HOST does. A value in the environment is ignored with the warning HOSTNAME is retired and ignored: it never bound anything; set LISTEN_HOST, except the pod or container name that every container runtime puts there, which never warns. A stored control plane override named HOSTNAME is dropped from a write with a warning, like STATE_MODE.
  • The control plane is stricter. It rejects an override that does not parse as the setting's type.

General​

VariableTypeDefaultAppliesDescription
LOG_LEVELtrace, debug, info, warn, warning, error, fatal, panic, disabledinfoliveMinimum log level, in any letter case. warning is the same as warn. A value that is not a level name logs LOG_LEVEL "x" is not a level name; logging at info and runs at info.
USE_CONSOLE_LOGSboolfalserestartWrites human readable console lines instead of JSON. Keep it false wherever a log platform ingests the output.

Routing​

VariableTypeDefaultAppliesDescription
DOMAIN_MAPJSONnoneliveMaps each request Host to an upstream and its per domain settings. See DOMAIN_MAP. A standalone relay needs at least one entry. A managed relay can receive the map from the control plane instead.
MAX_REQUEST_BODY_MIBint0liveInclusive cap, in MiB, on the plaintext request body. Exactly the cap passes; one byte more is answered 481 body_too_large. 0 means unlimited. Pass through routes are never capped. See Limits and scaling.
MAX_CONTROL_BODY_MIBint4liveCap, in MiB, on the JSON bodies of /api/mte-pair and /api/mte-keepalive. Over the cap is answered 481 body_too_large. 0 means unlimited.
FORWARD_HEADERSbooltrueliveStamps X-Forwarded-Host, X-Forwarded-Proto, and X-Forwarded-For on upstream requests. Turn it off only for an upstream that rejects them. It does not change the per domain preserve_host setting.

Server​

VariableTypeDefaultAppliesDescription
LISTEN_HOSTstring0.0.0.0restartAddress the relay listener binds. 0.0.0.0 is every interface, 127.0.0.1 loopback only; an IPv6 address may be written with or without brackets. Leave it unset in a container. With MODE=control the control plane ignores it and binds every interface.
LISTEN_PORTint8080restartRelay listen port, from 1 to 65535. Any other value refuses to start. With MODE=control it is the control plane's listen port.
PORTint8080restartAlias of LISTEN_PORT, kept for 4.x configurations. LISTEN_PORT wins when both are set, and a disagreement is logged once. Set LISTEN_PORT in new files.
HEALTH_CHECK_PATHstringemptyliveHealth check path on the relay port, for a load balancer or a security scanner that cannot reach the probe port. Empty means off, so an upgrade changes nothing. GET and HEAD at this path answer 200 {"status":"ready"} while the relay serves and 503 {"status":"not_ready"} once shutdown begins, for any Host, before Host resolution, CORS, rate limits, and the access log. HEAD sends no body. Any other method falls through to normal routing. Set it in the environment or in the control plane, where it is a Server group live field. See Health checks and scanners and the validation rules.
DEFAULT_POOL_SIZEint250restartIdle encoder and decoder instances kept by each of the four codec pools (MTE encoders, MTE decoders, MKE encoders, MKE decoders). The pools fill to this size at startup. A request that finds its pool empty creates a new instance, and an instance returned to a full pool is discarded.
MAX_POOL_SIZE_LIMITint100000restartUpper bound on DEFAULT_POOL_SIZE. A larger pool size is reduced to this value.
SESSION_TIMEOUT_MINUTESint120restartIdle timeout for pairs and for outbound relay clients. Traffic on a pair and keepalive calls refresh it. Advertised in discovery as sessionTimeoutSeconds.
HTTP_CLIENT_TIMEOUT_SECONDSint30restartHow long the relay waits for an inbound domain's upstream response headers. It does not cut off a response body that is already streaming. On an outbound domain it caps each auth, pair, and keepalive call to the next relay instead.
HTTP_MAX_IDLE_CONNS_PER_HOSTint1024restartIdle keep alive connections kept per upstream host.

MTE​

VariableTypeDefaultAppliesDescription
COMPANY_NAMEstringEclypses IncrestartMTE license company name.
LICENSE_KEYstring, sensitivedevelopment keyrestartMTE license key. The default is a development license. Set your production license.
KYBER_STRENGTH512, 768, 10241024restartKyber key exchange strength. Both ends of a pair must use the same strength, and it is advertised in discovery. The browser engine always uses 1024, so keep the default on a relay that serves browsers.
USE_MKEbooltruerestartEncode type the relay uses as a client on its outbound domains: MKE when true, standard MTE when false. Inbound, the relay decodes whichever type each request frame declares.
SEQUENCE_WINDOWint-63restartMTE decoder sequence window. Advertised in discovery, and both ends of a pair use it.
TIME_WINDOWint1000restartMTE decoder time window. Advertised in discovery, and both ends of a pair use it.

Protocol​

Frame version 2 bounds and timers, and the rate limit settings. Discovery advertises all of them except RESPONSE_COALESCE_MS, RATE_LIMITS, and TRUSTED_PROXIES, so clients read them from the relay instead of hardcoding them. See Discovery.

VariableTypeDefaultAppliesDescription
MAX_FRAME_BYTESint65536restartLargest frame payload accepted, in bytes. Advertised as maxFrameBytes and maxMessageBytes. Minimum 4096. The relay verifies a whole frame before it releases any plaintext, so a larger frame is not faster.
MAX_METADATA_BYTES_MKEint61439restartBound on the metadata JSON (method, path, headers) under MKE. Enforced and advertised. At least 1024, and at most MAX_FRAME_BYTES minus 1024.
MAX_METADATA_BYTES_MTEint7168restartBound on the metadata JSON under standard MTE. Enforced and advertised. At least 256, and 8 times the value plus 16 must fit in MAX_FRAME_BYTES.
MAX_PAIRS_PER_BATCHint100restartPairs accepted in one pairing request. At least 1.
MAX_PAIRS_PER_CLIENTint2048 Since 5.0.1restartPairs one client may hold, and the most pair ids one keepalive call may drop. At least 1. An outbound relay clamps its CLIENT_MAX_PAIRS to this value, so keep it at or above the largest CLIENT_MAX_PAIRS that pairs with this relay. Relay 5.0.0 shipped with 200.
MAX_PAIR_BYTESint1073741824restartPlaintext bytes per direction before a connection rekeys; the default is 1 GiB. Advertised as maxPairBytes for connection transports. The HTTP relay advertises it and does not enforce it. 0 takes the default and never means unlimited.
MAX_PAIR_MIBint1024restartAlias of MAX_PAIR_BYTES in MiB, kept for 4.x configurations. MAX_PAIR_BYTES wins when both are set, and a disagreement is logged once.
MAX_PAIR_SECONDSint86400restartSeconds before a connection rekeys. Advertised as maxPairSeconds for connection transports. The HTTP relay advertises it and does not enforce it. 0 takes the default.
TOKEN_MAX_AGE_SECONDSint86400restartMaximum age of a client token, checked at pair and keepalive. The data path checks only the token signature. At least 60.
REQUEST_SECONDSint30restartSilence deadline between request frames and for reading the whole request. At least 1. Per domain override: request_seconds.
RESPONSE_SECONDSint0restartBound on a whole response. 0 means unbounded, and the idle deadline applies. Per domain override: response_seconds.
IDLE_TIMEOUT_SECONDSint90restartSilence deadline between response frames. Advertised as idleTimeoutSeconds, which connection transports also use as their idle timeout; the HTTP relay's own keep alive idle timeout is a fixed 60 seconds. At least 1. Per domain override: idle_seconds.
PING_INTERVAL_SECONDSint25restartPING cadence advertised to connection clients. Must be below IDLE_TIMEOUT_SECONDS. The default 25 seconds stays under the 30 second idle timers common on proxies. Per domain override: ping_seconds.
DRAIN_SECONDSint30restartShutdown budget. After SIGTERM, readiness turns 503 stopping, the relay listener stops accepting, requests in flight drain for up to this many seconds, then the relay closes its state store and the probe listener closes last. Advertised as drainSeconds for connection transports, where it is also the time between GOAWAY and closing what remains on a connection. 0 takes the default. See Keepalive and timeouts.
RESPONSE_COALESCE_MSint2restartMilliseconds a streamed response DATA frame stays open after its first byte, so small writes from a paced upstream share a frame. 0 turns it off. At most 1000. Per domain override: response_coalesce_ms.
RATE_LIMITSbooltruerestartPer source and per client rate limits on auth, pair, and keepalive, answered 488 rate_limited with Retry-After. false turns every token bucket limiter off. See Limits and scaling.
TRUSTED_PROXIESstringnonerestartComma separated IP addresses and CIDRs of the load balancers and reverse proxies in front of the relay. For a request from one of them, the per source auth and pair limits key on the client address that X-Forwarded-For names instead of on the proxy. Empty keys every request on its peer address. See Limits and scaling.

Outbound client​

These apply to the client the relay runs toward the next relay on an outbound domain, which is how MTE API Relay chains work. The relay keeps one outbound client per outbound host.

VariableTypeDefaultAppliesDescription
CLIENT_INITIAL_PAIRSint2restartPairs created before the first request. The pool then fills to CLIENT_MIN_PAIRS in the background. At least 1.
CLIENT_MIN_PAIRSint25restartMinimum pair pool size. At least 1.
CLIENT_MAX_PAIRSint1024 Since 5.0.1restartMaximum pair pool size. A request holds one pair from encoding until its response ends, so this is the number of requests one replica can have in flight through one outbound host. At least CLIENT_MIN_PAIRS, and clamped to the receiving relay's MAX_PAIRS_PER_CLIENT with a warning. Set both to the same value to pin a fixed pool; setup fills to it one batch at a time. Relay 5.0.0 shipped with 100.
CLIENT_REFILL_THRESHOLDint10restartRefill the pool when available pairs fall to this value or fewer, or when requests are waiting for a pair. Each refill is sized to the requests waiting plus this margin, and to at least half the pairs in use, up to MAX_PAIRS_PER_BATCH; the next one starts as soon as it lands. From 0 to one below CLIENT_MAX_PAIRS. When it is unset and CLIENT_MAX_PAIRS is 10 or lower, it becomes one below the maximum.
CLIENT_PAIR_ACQUIRE_WAIT_MSint1000 Since 5.0.1restartHow long a request waits for a free pair before erroring. Requests wait in arrival order. Past the wait the outbound domain answers 485 upstream_capacity with Retry-After. At least 0. Relay 5.0.0 shipped with 250.

Redis​

The tuning values apply only when REDIS_URL is set.

VariableTypeDefaultAppliesDescription
REDIS_URLstring, sensitivenonerestartRedis URL for shared pair state. Needed when two or more replicas serve the same clients. Without it each relay keeps pair state in its own memory.
REDIS_POOL_SIZEint20restartRedis connection pool size per relay instance.
REDIS_MIN_IDLE_CONNSint5restartMinimum idle Redis connections.
REDIS_POOL_TIMEOUT_SECONDSint4restartWait for a pooled Redis connection before failing.
REDIS_DIAL_TIMEOUT_SECONDSint5restartRedis dial timeout.
REDIS_READ_TIMEOUT_SECONDSint3restartRedis read timeout.
REDIS_WRITE_TIMEOUT_SECONDSint3restartRedis write timeout.
REDIS_MAX_RETRIESint1restartRedis command retry count.
REDIS_OP_TIMEOUT_SECONDSint3restartTimeout for each state store operation.

Diagnostics​

Everything here is off by default. Turn it on for a bounded measurement, not as a steady state.

VariableTypeDefaultAppliesDescription
ENABLE_PPROFboolfalserestartServes Go pprof profiles on PPROF_PORT. The endpoint has no authentication, so keep that port off public networks.
PPROF_PORTint6060restartpprof listen port. From 1 to 65535 when pprof is on.
MUTEX_PROFILE_FRACTIONint1restartMutex profile sampling fraction, used with pprof.
BLOCK_PROFILE_RATEint1restartBlock profile sampling rate, used with pprof.
ENABLE_PERF_STATSboolfalserestartEmits periodic perf stats log events.
PERF_STATS_INTERVALint10restartPerf stats interval in seconds. Must be above 0 when perf stats are on.

Deployment settings​

These are read only from the environment. The control plane cannot override them, because they decide how a process starts and finds its control plane.

VariableDefaultRead byDescription
MODEunsetbothcontrol runs the control plane instead of the relay. Anything else runs the relay.
CONTROL_PLANE_URLnoneworkerAbsolute http:// or https:// URL of the control plane. Enables management. Set it together with CONTROL_PLANE_TOKEN; one without the other stops the worker at startup.
CONTROL_PLANE_TOKENnonebothShared bearer token. The control plane refuses to start without it, and each managed worker sends it on every poll.
CONTROL_PLANE_POLL_SECONDS3workerPoll interval, with 20 percent jitter. A value below 1 or not a number keeps the default.
CONTROL_PLANE_DATA_DIRdatacontrol planeDirectory for the stored configuration, its history, service tokens, and the session signing secret. A relative path resolves against the working directory. Mount a volume here.
CONTROL_PLANE_INITIAL_CONFIGnonecontrol planeJSON object of setting name to value that becomes the first stored configuration, so no setup wizard is needed. Applied once, when the data directory has never held a configuration, and ignored after that. Object values such as DOMAIN_MAP may be written as JSON objects. Invalid JSON, an unknown setting, or a value that fails validation stops the control plane at startup. See Preset configuration instead of the wizard.
CONTROL_PLANE_SETUP_HINTSnonecontrol planeJSON object of setting name to value that the setup wizard prefills, for example {"REDIS_URL":"redis://redis:6379"}. Unknown settings and values that fail validation are dropped.
PROBE_PORT9091workerLiveness (GET /healthz) and readiness (GET /readyz) listener, separate from the relay port, which serves neither path. Both take GET and HEAD. 0 disables it. Keep the probe port off public networks: it is for the orchestrator or load balancer only. A load balancer that can only reach the relay port uses HEALTH_CHECK_PATH or GET /api/mte-echo instead.
PROBE_ADDRall interfacesworkerAddress the probe listener binds, without a port, for example 127.0.0.1 on a shared host.
ADMIN_USERNAMEadmincontrol planeAdmin panel user name.
ADMIN_PWbuilt in defaultcontrol planeAdmin panel password. Set your own before anyone can reach the panel; the panel warns while the default is in use.
ADMIN_JWT_SECRETnonecontrol planeSeeds the admin session signing secret on first boot. After that the copy stored in CONTROL_PLANE_DATA_DIR wins. A value under 32 bytes, or one copied from a published example, is replaced by a generated secret at startup Since 5.0.1. Usually left unset.
RELAY_RUNTIMEdetectedworkerPins the runtime name the fleet view shows and builds restart commands for. Detection reports kubernetes, ecs, docker, or host. Display only.
LOCAL_STATE_CACHEfalseworkerServes pair state reads from memory and writes through to Redis. Applies only with REDIS_URL, and is correct only when a load balancer routes each client to one replica. See Limits and scaling.

Validation rules​

A relay refuses a configuration that breaks any of these rules. A standalone relay exits at startup with the reason. A managed worker keeps its current configuration and reports the reason in the control plane fleet view.

A 0 for MAX_FRAME_BYTES, MAX_METADATA_BYTES_MKE, MAX_METADATA_BYTES_MTE, MAX_PAIRS_PER_BATCH, MAX_PAIRS_PER_CLIENT, MAX_PAIR_BYTES, MAX_PAIR_SECONDS, TOKEN_MAX_AGE_SECONDS, REQUEST_SECONDS, IDLE_TIMEOUT_SECONDS, PING_INTERVAL_SECONDS, DRAIN_SECONDS, or CLIENT_INITIAL_PAIRS is not refused. It takes the default and never means unlimited.

  • LISTEN_PORT, and its alias PORT, is a port number from 1 to 65535.
  • KYBER_STRENGTH is 512, 768, or 1024.
  • MAX_FRAME_BYTES is at least 4096.
  • MAX_METADATA_BYTES_MKE is at least 1024 and MAX_METADATA_BYTES_MTE at least 256.
  • 8 times MAX_METADATA_BYTES_MTE plus 16, and MAX_METADATA_BYTES_MKE plus 1024, each fit in MAX_FRAME_BYTES.
  • MAX_PAIRS_PER_BATCH and MAX_PAIRS_PER_CLIENT are at least 1.
  • TOKEN_MAX_AGE_SECONDS is at least 60.
  • REQUEST_SECONDS, IDLE_TIMEOUT_SECONDS, and PING_INTERVAL_SECONDS are at least 1; RESPONSE_SECONDS and DRAIN_SECONDS at least 0.
  • PING_INTERVAL_SECONDS is below IDLE_TIMEOUT_SECONDS.
  • RESPONSE_COALESCE_MS is from 0 to 1000.
  • CLIENT_MIN_PAIRS and CLIENT_INITIAL_PAIRS are at least 1, CLIENT_MAX_PAIRS is at least CLIENT_MIN_PAIRS, CLIENT_REFILL_THRESHOLD is from 0 to one below CLIENT_MAX_PAIRS, and CLIENT_PAIR_ACQUIRE_WAIT_MS is at least 0.
  • With ENABLE_PERF_STATS on, PERF_STATS_INTERVAL is above 0. With ENABLE_PPROF on, PPROF_PORT is from 1 to 65535.
  • TRUSTED_PROXIES holds only IP addresses and CIDRs. A host name, a CIDR with host bits set such as 10.0.0.1/8, an address with an IPv6 zone, or an entry that covers every address, such as 0.0.0.0/0, is refused.
  • HEALTH_CHECK_PATH, when set, is an absolute, canonical path: no trailing slash, no // or dot segments, no wildcard, query, fragment, whitespace, or percent escapes, at most 256 bytes, not /, and not /api/mte-relay, /api/mte-echo, /api/mte-pair, or /api/mte-keepalive. A rejected value fails startup, and on the control plane the dry run and the write.
  • DOMAIN_MAP passes the structural rules on the DOMAIN_MAP page.

MRS and MAR images​

Both images build the same relay source. They differ in the MTE library build each binary links, and a client build pairs only with a server build, while an ANY build pairs only with another ANY build:

ImageMTE library buildPairs with
MTE Relay Server (MRS)serverClient builds: the browser engine and the mobile SDKs
MTE API Relay (MAR)ANYAnother MAR, which is why both ends of a relay to relay chain run the MAR image

A mismatch fails from the first request. An outbound relay compares the next relay's advertised mteProfile and refuses to pair with a different build, so the calling service gets 502 upstream_connect_failed and the outbound relay logs mteProfile mismatch. A client SDK pointed at the wrong image fails at setup or on its first request.