Octopus
1.x
Docs/Octopus/Protocols
Open

Reading2 min
Updated31 Jul 2026
Sourcev1/protocols/index.mdx

Protocols

Octopus is an HTTP-based reverse proxy. Every request arrives over the same listener, and the gateway inspects each one to decide how to forward it. There is no per-protocol port and no protocol field on a route — protocol handling is selected per request from the method, headers, and (for GraphQL) the path.

This section documents exactly what the gateway does for each protocol, grounded in the handler code. Where support is partial, it says so.

Support matrix01

ProtocolStatusWhat is actually supported
HTTP/1.1 & HTTP/2SupportedReverse proxy with connection pooling. The listener auto-negotiates HTTP/1.1 or HTTP/2 (prior-knowledge h2c) per connection. This is the default path for all traffic that is not detected as one of the protocols below.
WebSocketSupportedRFC 6455 upgrade handshake (version 13), then a full bidirectional frame proxy with keepalive pings and a close handshake.
Server-Sent Events (SSE)SupportedStreaming proxy — the upstream response body is forwarded to the client without buffering. Triggered by Accept: text/event-stream.
gRPCPartialTransparent proxy over HTTP/2 to a plaintext (h2c) upstream. Metadata and grpc-timeout deadlines are forwarded. The request body is buffered, so true client/bidirectional streaming RPCs are not streamed. No reflection proxy or transcoding.
GraphQLStub onlyThe built-in /graphql handler parses the request and serves a minimal placeholder; it does not proxy to a GraphQL upstream or federate. To proxy GraphQL today, route /graphql as a normal HTTP route. See GraphQL.
Warning

There is no WebTransport or HTTP/3 module in the codebase. HTTP/3 is not implemented and is not exposed in configuration.

How protocol routing works02

The request handler checks for protocols in a fixed order, before it buffers the request body. The first match wins:

  1. WebSocket — if the request carries Upgrade: websocket together with a Connection: Upgrade token, it is handled as a WebSocket upgrade. This must run before body buffering so hyper's upgrade future is preserved.

  2. SSE — if the Accept header contains text/event-stream, the request is handled as a streaming Server-Sent Events proxy.

  3. gRPC — if the Content-Type starts with application/grpc (or application/grpc-web / application/grpc-web-text), the request is handled by the gRPC proxy.

  4. Everything else — the body is buffered and the request flows through the normal HTTP path: registered protocol handlers (the GraphQL stub and a fallback gRPC handler), then the middleware chain, then the reverse proxy.

In all cases the upstream is selected by the router using the request host, method, and path — the same matching described in Routing. Detection only decides how the request is proxied; the route decides where. A WebSocket, SSE, or gRPC request to a path with no matching route is rejected.

Note

Because detection is header- and method-driven, a single upstream can serve plain HTTP, WebSocket, and SSE on the same route. You do not declare the protocol in the route — you only point the path at an upstream. See Routes.

Per-protocol pages03