mwitkow/grpc-proxy
mwitkow/grpc-proxy has 1,051 GitHub stars and 226 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-09 11:29 UTC. Last push 2026-03-18.
gRPC proxy is a Go reverse proxy that allows for rich routing of gRPC calls with minimum overhead.
Measured star growth
- in 24h
- 0
- in 7 days
- Collecting history
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
README.md
OriginalgRPC Proxy
gRPC Go Proxy server
Project Goal
Build a transparent reverse proxy for gRPC targets that will make it easy to expose gRPC services over the internet. This includes:
- no needed knowledge of the semantics of requests exchanged in the call (independent rollouts)
- easy, declarative definition of backends and their mappings to frontends
- simple round-robin load balancing of inbound requests from a single connection to multiple backends
The project now exists as a proof of concept, with the key piece being the proxy package that
is a generic gRPC reverse proxy handler.
Proxy Handler
The package proxy contains a generic gRPC reverse proxy handler that allows a gRPC server to
not know about registered handlers or their data types. Please consult the docs, here's an exaple usage.
You can call proxy.NewProxy to create a *grpc.Server that proxies requests.
director = func(ctx context.Context, fullMethodName string) (context.Context, *grpc.ClientConn, error) {
// Make sure we never forward internal services.
if strings.HasPrefix(fullMethodName, "/com.example.internal.") {
return nil, nil, status.Errorf(codes.Unimplemented, "Unknown method")
}
md, ok := metadata.FromIncomingContext(ctx)
if ok {
// Decide on which backend to dial
if val, exists := md[":authority"]; exists && val[0] == "staging.api.example.com" {
// Make sure we use DialContext so the dialing can be cancelled/time out together with the context.
conn, err := grpc.DialContext(ctx, "api-service.staging.svc.local", grpc.WithCodec(proxy.Codec()))
return ctx, conn, err
} else if val, exists := md[":authority"]; exists && val[0] == "api.example.com" {
conn, err := grpc.DialContext(ctx, "api-service.prod.svc.local", grpc.WithCodec(proxy.Codec()))
return ctx, conn, err
}
}
return nil, nil, status.Errorf(codes.Unimplemented, "Unknown method")
}
Then you need to register it with a grpc.Server. The server may have other handlers that will be served
locally.
server := grpc.NewServer(
grpc.CustomCodec(proxy.Codec()),
grpc.UnknownServiceHandler(proxy.TransparentHandler(director)))
pb_test.RegisterTestServiceServer(server, &testImpl{})
Testing
To make debugging a bit simpler, there are some helpers.
testservice contains a method TestTestServiceServerImpl which performs a complete test against
the reference implementation of the TestServiceServer.
In proxy_test.go, the test framework spins up a TestServiceServer that it tests the proxy
against. To make debugging a bit simpler (eg. if the developer needs to step into
google.golang.org/grpc methods), this TestServiceServer can be provided by a server by
passing -test-backend=addr to go test. A simple, local-only implementation of
TestServiceServer exists in testservice/server.
License
grpc-proxy is released under the Apache 2.0 license. See LICENSE.txt.
Explore related projects
codecrafters-io/build-your-own-x
Master programming by recreating your favorite technologies from scratch.
561,347 starspublic-apis/public-apis
A collective list of free APIs
497,596 starsmorluto/rea
Reverse engineer anything with agents, from app behavior down to native binaries.
446,738 starsopenclaw/openclaw
The AI that really does things. Any OS. Any Platform. The lobster way. 🦞
394,252 stars