Gateway Service
The Gateway is the public entry point of a WebStream deployment. It terminates SSL, authenticates users, resolves their entitlements, and proxies every browser connection — HTTP and WebSocket — to the right streamer on the right session host. It also hosts the built-in IAM control plane and the registry that backends and streamers report into.
Function
Started with webstream.exe -gw (or -gateway), the Gateway performs six jobs:
- SSL termination. Accepts HTTPS on the public IP using the configured PFX certificate; backends run plain HTTP on the private network.
- Load balancing. Distributes new sessions across registered backends using RoundRobin, LeastConnections, or Weighted strategies, with sticky session affinity so a client always returns to the same backend.
- Session brokering. On workspace launch it selects a backend, stores the workspace configuration, and injects the entitlement contract into every proxied request as HTTP headers.
- IAM hosting. With
accessManagement.mode = builtin (the default), the full Access Management API runs in-process — path-routed under /iam/* with no HTTP hop.
- Health monitoring. Continuously probes each backend and removes unreachable hosts from routing.
- Licence registry. Tracks active streamer GUIDs against the licensed session cap via periodic check-ins.
Ports and endpoints
| Listener | Port | Purpose |
| HTTPS | 443 | Public browser traffic (when the PFX certificate is present). |
| HTTP | gateway.port (default 9000) | Backend registration/heartbeat and internal traffic. |
Message contracts
Inbound — from session hosts (backends)
| Endpoint | Method | Frequency | Payload |
/gateway/register | POST | Once at backend startup (retried every 30 s, up to 10 times) | { serverUrl, maxSessions, instanceType, ec2InstanceId, tags[], capabilities[], version } |
/gateway/heartbeat | POST | Every 10 s (config heartbeatInterval) | { serverUrl, status, activeSessions, maxSessions, instanceType, tags[], cpuUsage, memoryUsage, timestamp } |
/gateway/unregister | POST | Backend shutdown | { serverUrl } |
Inbound — from streamers (licence registry)
| Endpoint | Method | Frequency | Payload / response |
/gateway/license/streamer-checkin | POST | Every 15 s per active streamer | { streamerGuid } → 200 OK, 403 (licence), or 409 (capacity) |
/gateway/license/streamer-checkout | POST | Session logoff / streamer exit | { streamerGuid } → { success, activeStreamers } |
Inbound — from browsers
| Endpoint | Method | Purpose |
/iam/auth/login, /iam/* | various | Authentication and the full IAM API (built-in mode). Returns a JWT used on all subsequent calls. |
/gateway/session/select | POST | Workspace launch. Body { workspaceId, workspaceType, appId, appExe, appArgs } with X-Session-ID and Authorization: Bearer headers. Reserves a concurrency slot and pins the session to a backend. |
/gateway/session/release | POST | Workspace end; frees the concurrency slot. |
/gateway/session/status | GET | Reconnect preflight; reports current session state. |
/getConnection | GET | Proxied to the pinned backend; returns the streamer connection details for the session. |
/capture, /control, /audio | WebSocket | Proxied through to the session's streamer for the life of the session. |
/gateway/health | GET | Plain OK liveness probe (for load balancers). |
After /gateway/session/select, the gateway injects the workspace contract into proxied requests as headers: X-Workspace-ID, X-Workspace-Name, X-Workspace-Type, X-App-ID, X-App-Exe, X-App-Args, X-User-ID, X-Username, X-Org-ID, and X-Policy-JSON (base64). The session host and streamer act on these — they never query IAM directly.
Inbound — MCP proxy
| Path | Auth | Routed to |
/mcp/api/* | X-MCP-Key header, validated against <mcpApiKeys> | Metrics Engine (http://localhost:9009/api/*) |
/mcp/iam/* | X-MCP-Key header | In-process IAM handlers |
Outbound — health probes
| Endpoint | Method | Frequency | Notes |
{backendUrl}/health | GET | Adaptive: 1 s while a backend is unstable, 10 s once stable (config healthCheck.interval) | Timeout 8 s; a backend is marked Unreachable after 4 consecutive failures (failureThreshold) and healthy again after 2 successes (successThreshold). |
Configuration
The Gateway consumes the <gateway> section of app.config.xml, plus the IAM and MCP sections:
| Property | Purpose |
gateway.enabled, gateway.publicIP, gateway.port | Enable gateway mode and set the public bind address and internal port. |
gateway.elevateGatewayPriority | Run the process at AboveNormal priority for WebSocket responsiveness. |
gateway.loadBalancing.strategy | RoundRobin, LeastConnections, or Weighted. |
gateway.loadBalancing.sessionAffinityTimeout | Sticky-session window in seconds (default 3600). |
gateway.healthCheck.interval / timeout / failureThreshold / successThreshold | Backend probe tuning. Keep timeout ≥ 6 s and failureThreshold ≥ 3 so a backend busy with login provisioning is not flapped out of routing. |
webstreamSettings.serverPfxCertificateFile / serverPfxSecret | The certificate used for HTTPS termination. |
accessManagement.mode | builtin runs IAM in-process (recommended); standalone/external point at a separate Access Management service. |
mcpApiKeys | Named API keys for the /mcp/* proxy. If empty, all MCP requests are rejected with 401. |
Aligned settings on peer services
- Each session host's
gateway.backend.gatewayUrl must point at this gateway's HTTPS URL, and its heartbeatInterval should be shorter than the gateway's failure window.
- Streamers inherit the gateway URL from the same
gateway.backend block for licence check-ins.
- The MCP proxy target assumes the Metrics Engine is reachable at
metricsEngine.httpPort (default 9009) on the gateway host or its configured URL.