Nginx as Reverse Proxy with GRPC
While trying to setup Nginx as a reverse proxy with GRPC, I had to spend a few hours to go through the GRPC, NGINX tutorial to figure out the process and make it work.
With this article of mine, I would like to help anyone to set it up quickly.
In this setup where Nginx acts as a reverse proxy, client makes a call to Nginx at port localhost:1449 which then routes the request to the server running at port localhost:1338.
Generate the certificates to establish secure connection (ssl)
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
Add -subj '/CN=localhost'
to suppress questions about the contents of the certificate (replace localhost
with your desired domain).
For our setup we will be using localhost as the CN value.
NGINX Configuration:
upstream dev {
server localhost:1338;
}server {listen 1449 ssl http2;ssl_certificate /tmp/server.crt; #Enter you certificate location
ssl_certificate_key /tmp/server.key;
location /helloworld.Greeter {
grpc_pass grpcs://dev;
}
}
The initial setup of the GRPC server can be done by following the below links. It already has ready to use code with all the stubs generated.
#GRPC hello world tutorial for python https://grpc.io/docs/quickstart/python/#Clone the sample repository git clone -b v1.23.0 https://github.com/grpc/grpccd examples/python/helloworld## if you want to make any changes to proto file and regenerate the stub , go to helloworld directory and run the below command python -m grpc_tools.protoc -I../../protos — python_out=. — grpc_python_out=. ../../protos/helloworld.proto
The highlighted code change is required to your server and client-side to make use of the ask certificate to verify the server and establish a secure connection between the client and server via Nginx.
Ensure to have the correct path for your certificates in Nginx config, server and client-side.
greeter_client.py
from __future__ import print_function
import loggingimport grpcimport helloworld_pb2
import helloworld_pb2_grpcdef run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.host = ‘localhost’
port = 1449with open(‘server.crt’, ‘rb’) as f: # path to you cert location
trusted_certs = f.read()credentials = grpc.ssl_channel_credentials(root_certificates=trusted_certs)
#channel = grpc.secure_channel(‘{}:{}’.format(host, port), credentials)with grpc.secure_channel(‘{}:{}’.format(host, port), credentials) as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name=’you’))
print(“Greeter client received: “ + response.message)if __name__ == ‘__main__’:
logging.basicConfig()
run()
greeter_server.py
from concurrent import futures
import time
import loggingimport grpcimport helloworld_pb2
import helloworld_pb2_grpc_ONE_DAY_IN_SECONDS = 60 * 60 * 24class Greeter(helloworld_pb2_grpc.GreeterServicer):def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message=’Hello, %s!’ % request.name)def serve():
port = ‘1338’with open(‘server.key’, ‘rb’) as f: #path to you key location
private_key = f.read()
with open(‘server.crt’, ‘rb’) as f: #path to your cert location
certificate_chain = f.read()server_credentials = grpc.ssl_server_credentials(
((private_key, certificate_chain,),))
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_secure_port(‘[::]:’+port, server_credentials)
#server.add_insecure_port(‘[::]:50051’)
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)if __name__ == ‘__main__’:
logging.basicConfig()
serve()
I hope this could help you get a basic understanding of setting up Nginx with GRPC.
Suggestions and inputs are always welcome.
Read more interesting software development and architecture articles.