Self-hosting
Self-hostingbeta10 min

Self-hosting the tunnel relay

Run the mcpg-cloud-relay broker inside your own trust boundary — listeners, authentication (static tokens or control-plane entitlements), TLS and DNS, rate limits, and how tunnelling gateways dial in.

The relay (mcpg-cloud-relay) is the broker that answers a reverse tunnel: self-hosted gateways dial out to it, and it host-routes inbound MCP requests back down the owning tunnel. The managed relay on mcpg.cloud is the zero-ops option; run your own when you want the relay inside your own trust boundary — the honest way to keep the relay from seeing anything you don't want it to (see the e2ee note in the tunnels guide).

This guide is operator-facing: the listeners, how to authenticate dial-ins, TLS and DNS, and how gateways point at your relay.

What it runs

The relay is a single binary with four listeners:

text
   self-hosted gateway ──dials out (wss)──▶  :7845  agent-accept
                                                    │  registers the tunnel
   MCP client ──────────https──────────────▶  :8080  public MCP (host-routed)
   same-org gateway ──/federate/<name>──────▶  :8081  federation ingress
   ops / probes ───────────────────────────▶  :9090  /healthz /readyz /metrics
  • Agent-accept (:7845) — where gateways dial in. Authenticated; TLS when configured.
  • Public MCP (:8080) — public tunnels are reachable here, host-routed by the first DNS label (<id>.<zone>).
  • Federation ingress (:8081) — same-org gateways reach a private tunnel by name for reverse federation.
  • Ops (:9090) — health, readiness, and Prometheus metrics.

Authentication (fail-closed)

The relay refuses to boot without an authenticator — a dial-in is only registered after it's authorized. Pick one:

Static token grants (simple self-host)

Map bearer tokens to orgs. Each dialing gateway presents its token in MCPG_TUNNEL_TOKEN.

bash
MCPG_RELAY_AUTH_TOKENS="tok_acme:acme,tok_globex:globex" \
mcpg-cloud-relay

Control-plane entitlements (managed posture)

Point the relay at a control plane and it authorizes every dial-in against the org's plan — resolution, suspension, allowed exposure/trust modes, and the concurrent-tunnel quota — and meters relayed bytes. This is what the managed service runs.

bash
MCPG_RELAY_CP_URL=https://cp.internal.example.com \
MCPG_RELAY_CP_TOKEN=$SHARED_RELAY_CP_TOKEN \
mcpg-cloud-relay

MCPG_RELAY_CP_TOKEN must equal the control plane's MCPG_CP_TUNNEL_API_TOKEN. When MCPG_RELAY_CP_URL is set, the CP is authoritative and takes precedence over a static token map.

Insecure (local dev only)

bash
MCPG_RELAY_AUTH=insecure-allow-all MCPG_RELAY_INSECURE_ORG=dev mcpg-cloud-relay

Accepts every dial-in and attributes it to one org. Never in production.

TLS and DNS

  • Agent-accept TLS. Provide a cert + key so the tunnel backbone is encrypted end to end into the relay. Absent, the agent-accept listener is plaintext (valid only behind a TLS-terminating load balancer).

    bash
    MCPG_RELAY_TLS_CERT=/etc/relay/tls.crt \
    MCPG_RELAY_TLS_KEY=/etc/relay/tls.key \
    mcpg-cloud-relay
    
  • Public tunnel zone. Public tunnels are minted at https://<id>.<zone>/mcp, where the zone defaults to tunnels.mcpg.cloud. Set your own and put a wildcard TLS cert for *.<zone> on the public listener (typically at your ingress/load balancer):

    bash
    MCPG_RELAY_ZONE=tunnels.example.com mcpg-cloud-relay
    

    Point a wildcard DNS record *.tunnels.example.com at the public listener. Private tunnels mint no hostname, so they need no DNS.

Rate limits and timeouts

Edge protection is on by default; tune per deployment:

Env varDefaultPurpose
MCPG_RELAY_IP_RATE / MCPG_RELAY_IP_BURST50 / 100Per-IP token bucket on the public edge
MCPG_RELAY_TUNNEL_RATE / MCPG_RELAY_TUNNEL_BURST200 / 400Per-tunnel token bucket
MCPG_RELAY_FORWARD_TIMEOUT_SECS30Wait for a response head before 504 (the streamed SSE body is not bounded by this)

Pointing gateways at your relay

On each tunnelling gateway, override the relay endpoint and, if your relay uses a private CA, trust it:

bash
export MCPG_TUNNEL_TOKEN=tok_acme                 # matches your relay's grant
export MCPG_TUNNEL_CA=/etc/mcpg/relay-ca.pem      # only if the relay uses a private CA
mcpg --config gw.yaml --tunnel wss://relay.example.com:7845

(--tunnel <wss-url> is shorthand for --tunnel --tunnel-relay <wss-url>.)

For a gateway that federates a private tunnel, point its gateway.server.tunnel_federation.relay_ingress_url at your relay's federation ingress (https://relay.example.com:8081). See the reverse-federation walkthrough.

Full environment reference

Env varFlagDefaultPurpose
MCPG_RELAY_AGENT_ADDR--agent-addr0.0.0.0:7845Agent-accept listener
MCPG_RELAY_PUBLIC_ADDR--public-addr0.0.0.0:8080Public MCP listener
MCPG_RELAY_FEDERATION_ADDR--federation-addr0.0.0.0:8081Federation ingress
MCPG_RELAY_OPS_ADDR--ops-addr0.0.0.0:9090Health / readiness / metrics
MCPG_RELAY_ZONE--zonetunnels.mcpg.cloudPublic URL zone (<id>.<zone>)
MCPG_RELAY_JSON_LOGS--json-logsoffJSON log output
MCPG_RELAY_AUTH_TOKENS--auth-tokensStatic token:org[,…] grants
MCPG_RELAY_AUTH--auth-modeinsecure-allow-all (dev only)
MCPG_RELAY_INSECURE_ORG--insecure-orgdevOrg under insecure-allow-all
MCPG_RELAY_CP_URL--cp-urlControl-plane URL (entitlement-aware auth)
MCPG_RELAY_CP_TOKEN--cp-tokenBearer to the CP tunnel API (required with cp-url)
MCPG_RELAY_TLS_CERT--tls-certAgent-accept TLS cert chain
MCPG_RELAY_TLS_KEY--tls-keyAgent-accept TLS key
MCPG_RELAY_IP_RATE / _IP_BURST--ip-rate / --ip-burst50 / 100Per-IP edge limit
MCPG_RELAY_TUNNEL_RATE / _TUNNEL_BURST--tunnel-rate / --tunnel-burst200 / 400Per-tunnel limit
MCPG_RELAY_FORWARD_TIMEOUT_SECS--forward-timeout-secs30Response-head timeout

High availability

The relay's tunnel registry is in memory, per replica: a tunnel is registered on the instance it dialed into, and the public/federation route resolves on that same instance. Running multiple replicas therefore needs sticky routing — a dialing gateway and the clients reaching its tunnel must land on the same replica (session affinity at the load balancer, or one relay per zone shard). Until shared-registry routing lands, size a single relay for your tunnel fan-out and scale by sharding zones, not by round-robin replicas.

Security checklist

  • An authenticator is configured (static tokens or CP) — the relay won't boot otherwise.
  • Agent-accept TLS is enabled, or a trusted proxy terminates TLS in front of it.
  • A wildcard cert covers *.<zone> on the public listener (if you allow public tunnels).
  • The ops listener (:9090) is not exposed to the internet.
  • Rate limits are sized for your edge.
  • Gateways trust the relay's CA (MCPG_TUNNEL_CA) if it isn't publicly rooted.

See also