Appearance
Hosting Gateway
The Hosting Gateway is the HTTP front door of a Matrix Host. It is the boundary between the unauthenticated browser world and the typed-actor bus underneath. Browsers, OAuth providers, webhook callers, and external monitors speak HTTP; the substrate speaks NATS request/reply. The gateway is the only piece of code allowed to translate between the two — and only for a closed list of boundary purposes.
Motivation
The gateway exists because the bus has no idea HTTP is a thing, and every HTTP-aware client (browsers, OAuth providers, uptime monitors, webhook senders) has no idea what a NATS subject is. Something has to bridge them, but only at the boundaries that genuinely cannot be avoided: serving the browser bundle, upgrading to a NATS WebSocket, handing back OAuth redirects, answering health probes, accepting webhooks, and shaking hands for federation. Anything beyond that closed list is either a documented compatibility projection for a non-bus-aware client or a bug — the bus itself is the authority on what is running and what can do what. Read these docs if you operate the gateway, are debugging a routing or asset issue, or are about to add a new /api/* endpoint and want to know why that is almost always the wrong move.
What this is, and why it exists
In docker-for-actors terms, the gateway is the substrate's ingress controller: not the app server, not the registry, not the directory of who runs what. It serves browser bundles, upgrades a same-origin path to NATS WebSocket, mints bootstrap credentials so a fresh tab can join the bus, and forwards OAuth redirects. Inventory questions — "what apps are running? what devices are linked? what runtimes exist?" — are bus questions answered by system.catalog, system.devices, system.runtimes. They are not gateway endpoints. That distinction is normative; see P1.43 — HTTP-API reduction.
The gateway ships as a normal Matrix package, @open-matrix/system-gateway-http. Its actor mounts at system.gateway.http (under system.gateway). The HTTP listener and route resolver live in the same runtime that mounts the actor.
Where this fits in the whole
This is substrate plumbing, not a vertical. The gateway has no UI of its own and no domain logic. It exists so that:
- Browsers can boot into the bus from a single same-origin URL.
- Each package's runtime can serve its own assets without sharing a filesystem with the gateway.
- Caddy (or any reverse proxy) has a single TCP target to terminate TLS in front of.
It runs in Tier 1 (a user's local Host) and Tier 2 (a hosted/VPS Host) identically. There is no separate cloud variant.
The closed list of HTTP boundaries
The gateway exposes HTTP endpoints only for boundaries the substrate cannot avoid:
- Browser-bootstrap credential issuance (
/api/identity/bootstrap,/api/identity/nats-creds). - OAuth redirects/callbacks (
/oauth/<provider>/callback). - Static asset serving for package webapps (
/apps/<appName>/<assetPath>and the public-namespace variants). - NATS WebSocket upgrade (
/nats-ws). - Health endpoint for external monitors (
/healthz). - Webhooks from external providers.
- Federation handshake (when federation lands).
Anything outside that list is either a documented projection for non-bus-aware clients (CI scripts, third-party uptime monitors) or a bug. Internal substrate consumers — the dashboard, Edge, navbar, catalog, agents — invoke bus actors directly, never HTTP.
Status: bus-is-authority migration in progress. Several historical endpoints (
/api/apps,/api/runtimes/*,/api/status) still serve projection data today and are being migrated. Treat them as compatibility projections; new code reads fromsystem.catalog,system.runtimes,system.devices. Tracker: P1.43.
Five-minute quickstart
Start a Host, hit the gateway, watch a static asset come out of a package's own runtime.
bash
# 1. Install + start a Host.
node projects/matrix-3/packages/hivecast/bin/hivecast.mjs install \
--home /tmp/matrix-home --no-start
node projects/matrix-3/packages/hivecast/bin/hivecast.mjs start \
--home /tmp/matrix-home
# 2. Liveness on the boundary endpoint that does NOT require auth.
curl -fsS http://127.0.0.1:3100/healthz | jq .
# {
# "ok": true,
# "status": "ok",
# "release": { "version": "...", "commit": "..." }
# }
# 3. Fetch a webapp asset. The gateway routes to the chat runtime's
# own MatrixHttpAssetEndpointActor; the file lives in chat's dist/.
curl -I http://127.0.0.1:3100/apps/chat/
# 4. Inventory questions go to the bus, NOT the gateway.
matrix invoke system.catalog catalog.list '{}'
matrix invoke system.runtimes runtimes.list '{}'
matrix invoke system.devices devices.list '{"includeOffline":true}'Step 4 is the load-bearing one. Note that matrix invoke opens a NATS connection to the bus. The gateway is involved only in step 3.
Conceptual map
| Question you have | Read |
|---|---|
| What does the gateway actually do, end to end? | Overview |
| Which URLs map to which Matrix actors? | Routes |
| How does a package's webapp reach the browser? | App Hosting |
| How do I keep it healthy / read its logs / roll it back? | Operations |
| What are the actor ops, schemas, and config keys? | Reference |
Where this lives in the code
| Concern | Path |
|---|---|
| HTTP listener (port, dispatch) | projects/matrix-3/packages/system-gateway-http/src/http-listener.ts |
| URL grammar parsing | projects/matrix-3/packages/system-gateway-http/src/http-routing.ts |
Gateway actors (SystemGatewayActor, SystemGatewayHttpActor, MatrixHttpAssetEndpointActor) | projects/matrix-3/packages/system-gateway-http/src/index.ts |
| Boundary HTTP surface (bootstrap, OAuth, projections) | projects/matrix-3/packages/system-gateway-http/src/host-platform-http-surface.ts |
| Runtime entry point | projects/matrix-3/packages/system-gateway-http/src/host-http-runtime.ts |
Release metadata for /healthz | projects/matrix-3/packages/system-gateway-http/src/release-metadata.ts |
| Manifest | projects/matrix-3/packages/system-gateway-http/matrix.json |
Sister docs
docs-runtime-host— the Host that supervises the gateway runtime.docs-package-lifecycle— how a package declares a webapp surface and gets a<appName>.httpasset endpoint.docs-registry—system.catalog/system.registry/system.packages, the bus actors that own the inventory the gateway used to expose over HTTP.
Caddy is a separate layer
Production deploys put Caddy in front of the gateway for TLS termination and per-host routing. The gateway is the origin Caddy proxies to. Caddy is not part of the gateway and not Matrix-aware. Local dev does not use Caddy. See Operations / TLS / Caddy integration.
Source: Live in the codebase under
projects/matrix-3/packages/system-gateway-http/. Runtime entry:host-http-runtime.ts. Actor classes:index.ts. Caddy configurations live separately inprojects/deploy-cloud/Caddyfile.bare.