Skip to main content

How it attaches

beacon-gateway is an Envoy External Processing (ext_proc) server. Envoy opens one gRPC stream per HTTP exchange and sends it the request and reply headers and bodies. Anything built on Envoy’s HTTP filter chain can use it: plain Envoy, Envoy Gateway and Istio gateways or sidecars. Envoy carries the provider’s own wire format, so beacon-gateway decodes the bodies the client sent and the provider returned. Only a POST with a body to a model endpoint is decoded. The path decides the protocol: Everything else (model lists, token counting, embeddings, OpenAI Assistants thread messages) passes through untouched.

What is supported

Envoy must see the request in plain text. Put the ext_proc filter on a listener where the client’s TLS is terminated (an API gateway, an egress gateway that originates TLS to the provider), not on a TCP passthrough.

Configure beacon-gateway

beacon-gateway.yaml
A body larger than max_body passes through unrecorded. The listener speaks plain gRPC with no authentication, so expose it only to Envoy.

Deploy with Envoy

gateway/deploy/envoy/envoy.yaml is a complete, observe-only configuration. The parts that matter:
envoy.yaml (excerpt)
  • Request BUFFERED. The request arrives whole and is sent in one message. Raise per_connection_buffer_limit_bytes on the listener and the provider cluster to match max_body (the example uses 32 MiB); Envoy’s 1 MiB default is too small for a long agent conversation.
  • Reply STREAMED. Each chunk is forwarded as soon as beacon-gateway acknowledges it, which it does at once, so streaming keeps its token-by-token latency.
  • The beacon_gateway cluster needs HTTP/2 (http2_protocol_options), as every gRPC cluster does.
  • Route timeout. Long generations outlast Envoy’s 15 s default; the example sets 600s.
beacon-gateway tells buffered from streamed bodies by what arrives, so no setting on its side has to match Envoy’s processing mode. Validate and run the example:
The example’s provider cluster points at a local test upstream. For a real provider, point it at api.anthropic.com:443 or api.openai.com:443 with an UpstreamTlsContext and set auto_host_rewrite: true on the route (both are in the file’s comments). Then point clients at Envoy, for example ANTHROPIC_BASE_URL=http://<envoy>:10000 for Claude Code.

Deploy with Envoy Gateway

Run beacon-gateway as a Deployment with a Service on port 4021, and attach it to the HTTPRoute that carries model traffic with an EnvoyExtensionPolicy:
envoy-extension-policy.yaml
Set the route’s request timeout high enough for long generations, and raise the proxy’s buffer limit (ClientTrafficPolicy connection.bufferLimit) to cover large requests. If the gateway authenticates callers with a SecurityPolicy JWT provider, use its claimToHeaders to put the caller’s claims on headers and name those headers in identity_headers.

Deploy with Istio

Insert the filter with an EnvoyFilter on the workload that terminates the model traffic, such as an egress gateway that originates TLS to the provider:
envoyfilter.yaml
Name the beacon-gateway Service port grpc (or set appProtocol: grpc) so Istio uses HTTP/2 to it. For a sidecar, use context: SIDECAR_OUTBOUND and select the workload’s labels instead; the sidecar sees plain text only when the application sends HTTP and the mesh originates TLS.

Troubleshooting

LLM gateways

What gateway collection records and the settings shared by every gateway.

LiteLLM

Attach to a LiteLLM proxy instead.