Deployment Notes
🏗️ Deployment lens: the gateway is one stateless-config, stateful-session process behind a front door. Everything here follows from that: route only MCP traffic to it, keep Redis close and trusted, and give stateful sessions affinity.
Front-Door Routing
The reference docker/nginx.conf shows the intended split:
location ^~ /contextforge-rsproxies to the gateway upstream.- Everything else — UI, management APIs, other ContextForge traffic — stays on the existing control-plane paths.
- The reference listener uses
backlog=4096 reuseportand configures upstream retries (error timeout http_502/503/504, 2 tries, 10 s window). For MCPPOSTbodies this effectively retries only connection-stage failures: nginx does not re-send non-idempotent requests once they reached an upstream, and MCP calls are not idempotent.
There is no production health endpoint today: /health is a with_tools
bootstrap helper served at /contextforge-rs/health, and production builds
compile it out. Use TCP-level checks or the exported metrics for liveness
until a real health endpoint exists. (The reference nginx config’s
location = /health predates this and does not match the gateway’s route.)
The cf-integration
harness runs the same split with the stock upstream control-plane stack and
rewrites public /servers/{id}/mcp to /contextforge-rs/servers/{id}/mcp.
TLS Choices
| Leg | Options |
|---|---|
| Front door to gateway | Plain HTTP on a trusted private network (the common shape behind nginx), or terminate TLS at the gateway with --tls-address plus certificate and key. Both listeners can run at once on different sockets. |
| Gateway to Redis | --redis-mode plain, TLS, or mTLS. Use TLS/mTLS across trust zones — Redis is the config trust boundary (see Security Model). |
| Gateway to backends | HTTPS-only by default; opt into plain HTTP or mTLS with --upstream-connection-mode. |
Session Affinity And Failover
Backend MCP sessions are local process state (Session Ownership):
- More than one replica requires sticky routing by
Mcp-session-id; the reference nginx config does not provide this, so today’s safe shapes are a single replica or a front door that adds stickiness. - On restart or failover, sessions are gone; clients must re-run
initialize. Design clients to treat a session-not-found error as “reinitialize”, not “retry”. - A Redis-backed user session store exists in code, but live backend services would still be process-local; a remote session story is future work.
- Inside one host, the same constraint applies to
--single-runtime false; see Concurrency And Runtime Model.
Redis Availability
Redis is required at startup and on every uncached config lookup. The
connection manager retries heavily (1,000 retries) rather than failing fast,
and the in-process cache (default 60 s) rides out short blips for warm
subjects. A cold subject during a Redis outage fails at config lookup; the
current Redis adapter reports failed GET calls as missing data, so the layer
returns 400 until Redis returns.
Images And Sizing
- CI builds
docker/Dockerfile(arust:1.96.1builder stage) on every push tomainand pushesghcr.io/<owner>/contextforge-gateway-rs:<version>, where the tag is the Cargo package version. There is nolatesttag — pin the version. - The reference Compose stack runs the gateway with raised limits worth
copying to real deployments:
nofile65535 and TCP tuning (tcp_fin_timeout=15, widened local port range) for high connection churn. - Size CPU with
--number-of-cpus(defaults to host CPU count) and keep the default single multi-thread runtime for stateful traffic. Memory scales with active sessions (live backend services) and the config caches (up to 50,000 entries each).
Deployment Checklist
- Front door routes only
/contextforge-rshere. - JWT verification key or secret in place and rotated with the control plane’s signing key.
- Redis reachable, TLS/mTLS across trust zones, write access restricted to
the control plane;
DATAPLANE_PUBLISHERenabled on the control plane. - Upstream connection mode matches the backend URL schemes.
- One replica per
Mcp-session-id(single replica or sticky routing). with_toolsdisabled in the production build.- Telemetry export pointed at the collector; see Telemetry And Diagnostics.