I have an existing setup using two cascaded nginx instances:
- the outer nginx is just doing TLS termination and forward to inner nginx
- the inner nginx is routing the requests to different applications (REST APIs)
Until now we were only using HTML pages and REST APIs. The routing of the outer nginx is pretty simple, it is mainly serving static HTML, the other traffic is forwarded to the inner nginx.
Now we want to support also grpc APIs. The problem with grpc is that the path of the requests are defined by the grpc interface proto, e.g. "acme.myapi/MyMethod". The routing of the requests of the outer nginx shall not depend on that interface definitions because the outer nginx shall not need to be changed when new grpc interfaces are added and there can even be an overlap in the url path between REST API and grpc, e.g both could begin with "/acme/". Also we have no control over the name of the proto package names and therefore the url path.
The grpc routing of the inner nginx is using the :authority header for the routing to the grpc applications. The configuration is updated dynamically when new applications are added.
All grpc calls shall be redirected to a specific endpoint of the inner nginx (grpc://127.0.0.1:50051), the REST API calls shall use another endpoint (https://127.0.0.1:4443/) of the inner nginx instance.
The easiest way from the perspective of the nginx configuration would be to use two different endpoints (different ports) also for the outer nginx. Unfortunately the organizational effort to open another port in the firewalls would be very high and is not accepted, so I need to use the same endpoint for all protocols.
This is the config I currently use and it works with the problems describe above:
location ~ ^acme\. { # "acme" is the grpc packagename
grpc_pass grpc://127.0.0.1:50051;
grpc_set_header "Host" $host;
grpc_read_timeout 1200s;
grpc_send_timeout 1200s;
client_body_timeout 1200s;
client_max_body_size 0;
}
location / {
proxy_pass https://127.0.0.1:4443/;
[...] # setting lots of other options
}
Here is the config I'd like to use (simplified to the minimum) but according to If is Evil… this cannot be used:
location / {
if ($http_content_type ~ ^application/grpc)
{
grpc_pass grpc://127.0.0.1:50051;
grpc_set_header "Host" $host;
grpc_read_timeout 1200s;
grpc_send_timeout 1200s;
client_body_timeout 1200s;
client_max_body_size 0;
}
normally I would use 'else' here, but this is not supported
if ($http_content_type !~ ^application/grpc)
{
# also set other REST API specific config options here, left out for brevity
proxy_pass https://127.0.0.1:4443/;
}
I get the following error from nginx:
nginx: [emerg] "grpc_set_header" directive is not allowed here in /etc/nginx/conf.d/my.conf.locations:80
In the end I need to be able to use the $http_content_type as a selector instead (or additionally) to the url path.
Is there any good solution for this requirements?