Gateway Relay & Cloudflare Tunnel
Connected gateways can run on machines behind NAT, firewalls, VPNs, or corporate networks. The gateway relay is a built-in reverse tunnel that lets these gateways receive inbound API traffic without opening any inbound ports. For production deployments that need a dedicated hostname or edge features, you can use Cloudflare Tunnel instead.
How the relay works
When a connected gateway starts, it derives a dedicated relay hostname from KEEPTRUSTS_API_URL and opens a persistent outbound WebSocket connection:
KEEPTRUSTS_API_URL=https://api.eu.keeptrusts.com
↓ automatic derivation
Gateway ──WSS──▶ wss://relay.eu.keeptrusts.com/v1/gateway/relay
The relay hostname is region-aware: the api. prefix in the API URL is replaced with relay. automatically. For example:
| API URL | Derived relay URL |
|---|---|
https://api.eu.keeptrusts.com | wss://relay.eu.keeptrusts.com/v1/gateway/relay |
https://api.us.keeptrusts.com | wss://relay.us.keeptrusts.com/v1/gateway/relay |
You do not need to configure the relay URL — it is derived automatically from the API URL.
- The gateway authenticates using its machine token (
KEEPTRUSTS_API_TOKEN). - It sends a registration message containing its
runtime_registration_id. - The control plane acknowledges and begins dispatching inbound API requests through the WebSocket.
- The relay client forwards each request to the local gateway HTTP server and sends the response back.
- Streaming responses (including SSE for LLM completions) are forwarded through the same channel.
If the WebSocket connection drops, the gateway reconnects automatically with exponential backoff (1 second initial delay, 30 second maximum).
Configuration
The relay is enabled by default for all connected gateways. No additional configuration is required — the gateway derives the relay endpoint automatically from KEEPTRUSTS_API_URL and uses the same environment variables you already set during installation:
| Variable | Purpose |
|---|---|
KEEPTRUSTS_API_URL | Control-plane URL — the relay hostname is derived from this automatically |
KEEPTRUSTS_API_TOKEN | Machine token used to authenticate the WebSocket |
KEEPTRUSTS_RUNTIME_REGISTRATION_ID | Gateway identity sent during registration |
The local gateway HTTP server listens on port 41002 by default. The relay client forwards dispatched requests to http://127.0.0.1:<gateway-port> with a 30-second per-request timeout.
Using Cloudflare Tunnel with gateways
For production deployments where you need a dedicated hostname, edge caching, enterprise compliance, or custom domain routing, use Cloudflare Tunnel to expose the gateway.
1. Install cloudflared
# macOS
brew install cloudflared
# Debian / Ubuntu
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \
| sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install -y cloudflared
2. Create a tunnel
cloudflared tunnel login
cloudflared tunnel create keeptrusts-gateway
3. Configure the tunnel
Create ~/.cloudflared/config.yml to route traffic to the local gateway:
tunnel: keeptrusts-gateway
credentials-file: /home/<user>/.cloudflared/<tunnel-id>.json
ingress:
- hostname: gateway.example.com
service: http://localhost:41002
- service: http_status:404
4. Set up DNS
cloudflared tunnel route dns keeptrusts-gateway gateway.example.com
This creates a CNAME record pointing gateway.example.com to the tunnel.
5. Start the tunnel
cloudflared tunnel run keeptrusts-gateway
For persistent operation, install cloudflared as a system service:
sudo cloudflared service install
6. Register the hostname with Keeptrusts
Update the gateway record so the platform knows its public address:
kt gateway update --name production --public-url https://gateway.example.com
Or set the public URL in the console Gateways page.
When to prefer Cloudflare Tunnel over the built-in relay
| Consideration | Built-in relay | Cloudflare Tunnel |
|---|---|---|
| Setup complexity | None — works out of the box | Requires cloudflared install and DNS |
| Dedicated hostname | Not applicable | Custom domain (e.g. gateway.example.com) |
| Edge features | Not applicable | DDoS protection, caching, access policies |
| Compliance | Traffic routes through Keeptrusts relay | Traffic routes through your Cloudflare account |
| Latency overhead | ~10–50 ms relay hop | Typically lower — direct edge-to-origin |
Both approaches can coexist. The built-in relay provides zero-config connectivity, while Cloudflare Tunnel gives you full control over the network path.
Monitoring
Console
The Gateways page in the console shows each gateway's relay connection status and last-seen timestamp.
CLI
kt gateway status --name production
The output includes relay connection state and the last heartbeat time.
Heartbeats
The control plane sends periodic WebSocket pings. If the gateway stops responding to pings, the platform marks it as disconnected. Reconnection happens automatically on the gateway side.
Troubleshooting
"relay connection failed"
- Verify
KEEPTRUSTS_API_URLis set and the host is reachable. - Confirm the firewall allows outbound HTTPS and WSS traffic on port 443.
- Check DNS resolution for both the API host and the derived relay host (e.g.
relay.eu.keeptrusts.com).
"authentication failed"
- The machine token may be expired or revoked. Rotate it in the console or via
kt auth token create. - Verify
KEEPTRUSTS_API_TOKENmatches the token assigned to this gateway.
High latency through the relay
The built-in relay adds approximately 10–50 ms of overhead per request. If latency is critical:
- Use Cloudflare Tunnel for a shorter network path.
- Place the gateway closer to the API consumers.
- Use direct connectivity if the network allows inbound traffic.
Gateway reconnects frequently
- Unstable network connections cause repeated backoff cycles. Check the host's network stability.
- If the gateway logs show the backoff reaching 30 seconds, the control plane may be temporarily unavailable — the gateway will recover automatically.