Octopus
1.x
Open

Reading3 min
Updated31 Jul 2026
Sourcev1/protocols/grpc.mdx

gRPC

Octopus proxies gRPC transparently over HTTP/2. It does not understand your .proto files — it forwards the gRPC framing, metadata, and trailers between client and upstream. There is no transcoding (JSON↔gRPC) and no reflection proxy.

Detection01

A request is treated as gRPC when its Content-Type begins with application/grpc. The gRPC-Web content types (application/grpc-web, application/grpc-web-text) are also recognized at detection time. Detection happens before body buffering so the proxy can use the HTTP/2 path.

How it is handled02

1

Validate. Only POST is accepted. gRPC paths must be /{package.Service}/{Method}; anything else is rejected with a gRPC UNIMPLEMENTED status (the gateway always replies with HTTP 200 and the gRPC status in headers, per the gRPC spec).

Route. The upstream is resolved by the normal router using the request host and the gRPC path — exactly like an HTTP route. Point a route at your gRPC upstream.

Forward headers. All headers are forwarded except hop-by-hop ones (connection, keep-alive, transfer-encoding, upgrade, the proxy-auth headers). te: trailers is always set, which gRPC over HTTP/2 requires. This means grpc-* metadata, authorization, and custom metadata pass straight through.

Propagate deadlines. If the request carries a grpc-timeout header, it is parsed and used as the upstream call timeout and re-sent to the upstream. With no grpc-timeout, a default 30-second timeout applies. On timeout the gateway returns gRPC DEADLINE_EXCEEDED.

Send over HTTP/2. The request is sent to the upstream over a pooled, multiplexed HTTP/2 connection. The upstream connection is plaintext HTTP/2 (h2c) — the gateway opens a TCP connection and performs an HTTP/2 handshake directly. The upstream response body is streamed back to the client.

If the upstream cannot be reached, the gateway returns gRPC UNAVAILABLE.

Warning

The request body is collected (buffered) in full before being sent to the upstream. This works for unary RPCs and is fine for server-streaming responses (the response is streamed back), but it means client-streaming and bidirectional-streaming RPCs are not truly streamed — the client's stream is buffered before forwarding. The handler code documents this as the known limitation of the current implementation.

Example route03

A gRPC upstream is just an HTTP/2 upstream and a route whose path is the gRPC service:

upstreams:
  - name: users-grpc
    instances:
      - id: users-grpc-1
        host: 127.0.0.1
        port: 50051

routes:
  - path: /users.UserService
    upstream: users-grpc

There is no protocol flag on the route — detection is driven by the application/grpc content type. The upstream must speak plaintext HTTP/2 (h2c).

Configuration block04

A top-level grpc configuration block exists (enabled, max_message_size, enable_reflection, enable_grpc_web, deadline_propagation, and a services service→upstream map). See gRPC configuration for the schema.

Warning

In the current build these grpc config fields are parsed and surfaced via the admin API, but the live gRPC proxy path does not read them: it uses built-in defaults, routes via the normal router (not the services map), and always propagates grpc-timeout when present. Treat enable_reflection, enable_grpc_web, max_message_size, and services as not yet wired into the proxy.

Limitations05

  • No reflection proxy. The server reflection service is not proxied or synthesized.

  • No transcoding. There is no JSON-to-gRPC (HTTP/JSON ↔ gRPC) translation.

  • gRPC-Web is not handled in the proxy path. Although gRPC-Web content types are detected, the proxy does not perform gRPC-Web ↔ gRPC framing translation.

  • Streaming is partial. Unary and server-streaming work; client-streaming and bidirectional streaming are buffered on the request side rather than streamed.

  • Plaintext upstream only. The HTTP/2 upstream connection is h2c (no TLS to the upstream).