Opened 8 years ago

Closed 6 years ago

Last modified 3 years ago

#923 closed enhancement (fixed)

Allow proxy_http_version 2.0

Reported by: mmarkus@… Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.9.x
Keywords: Cc:
uname -a:
nginx -V: 1.9.12

Description

We are working on migrating the service to service calls to gRPC. We use nginx as an gateway that proxies to a pool of gRPC servers (HTTP2.0).
Is there a plan to support this feature and if so an ETA for it? This would help Square to move forward but also seems like a pretty common setting for the gRPC enabled deployments.

Change History (20)

comment:1 by Maxim Dounin, 8 years ago

Resolution: wontfix
Status: newclosed

There are no plans to implement HTTP/2 support in the proxy module in the foreseeable future, see detailed answer here. If you want to use nginx to balance multiple servers, consider using the stream module to do this.

comment:2 by mmarkus@…, 8 years ago

Replying to mdounin:

There are no plans to implement HTTP/2 support in the proxy module in the foreseeable future, see detailed answer here. If you want to use nginx to balance multiple servers, consider using the stream module to do this.

Thanks for the quick response.
I don't think level 4 proxying would work for us, specifically in situations where a small number of clients are connected to a large pool of backend servers: each client would issue all its requests over the same TCP connection to the same backend server, potentially exhausting it.
Regarding your comment on the limit on number of simalteneous requests :the way I was thinking about load balancing is to have nginx dispatch different stream to different backend servers, which I think should solve the problem. (not very familiar with nginx/http2 so the idea might be way off)


Last edited 8 years ago by mmarkus@… (previous) (diff)

comment:3 by cicerocomp@…, 8 years ago

For those who come here and still need to make a proxy HTTP2 protocol:

https://nghttp2.org/blog/2015/03/24/proxying-grpc-with-nghttpx/

comment:4 by RoiEXLab@…, 7 years ago

Resolution: wontfix
Status: closedreopened

While it might be worse when using HTTP/2 instead of HTTP/1.1 between nginx and your server, not implementing such a feature has a huge downside.
On of the features of HTTP/2 is Server-Side pushes which are therefor not supported at all when using nginx as reverse proxy.
There is no workaround for this other than simply not using nginx and connect to the server directly.

comment:5 by Maxim Dounin, 7 years ago

HTTP/2 push has nothing to do with HTTP/2 support to upstreams, it can be easily (and likely more efficiently) implemented without using HTTP/2 to upstreams, see here.

comment:6 by Maxim Dounin, 7 years ago

Component: documentationnginx-core
Priority: criticalminor

comment:7 by cicerocomp@…, 7 years ago

I do not know if it should be critical, but it should be at least major

comment:8 by AlekSi@…, 6 years ago

Any update on this?

comment:9 by cicerocomp@…, 6 years ago

any

comment:10 by Valentin V. Bartenev, 6 years ago

The development of gRPC proxy is in progress. See: https://trac.nginx.org/nginx/roadmap

comment:11 by mcgrawia@…, 6 years ago

Hi, does anyone know if the gRPC proxy will support context based routing rules with the hostname/path? I am working on a use case using Kubernetes and trying to expose many different gRPC services through an nginx ingress controller. I see it is on the roadmap but can't find out any more details of what features will be included.

Thanks!

comment:12 by Maxim Dounin, 6 years ago

Resolution: fixed
Status: reopenedclosed

The gRPC proxy module has been committed and will be available in nginx 1.13.10.

comment:13 by tonyaw@…, 6 years ago

Hi, now nginx can support gRPC proxy( https://www.nginx.com/blog/nginx-1-13-10-grpc ), but looks like it still can't support HTTP2 proxy. Since gRPC is based on HTTP2, is there any reason not to implement it, and is there any plan to implement it in the future?

comment:14 by tonyaw@…, 6 years ago

I realized that nginx can work as HTTP2 reversed proxy actually. :-)
Looks like the grpc proxy function can work as a HTTP2 proxy.

  1. The following is my configuration:
error_log stderr debug;


events {
       worker_connections  1024;
}


http {
     upstream grpcservers {
         server nghttp2servernginx-0.nghttp2-server-svc.tonyaw.svc.cluster.local.:5555;
         server nghttp2servernginx-1.nghttp2-server-svc.tonyaw.svc.cluster.local.:5555;
         server nghttp2servernginx-2.nghttp2-server-svc.tonyaw.svc.cluster.local.:5555;
     }


     server {
         listen 7777 http2;

         access_log /dev/stdout;

         location / {
             grpc_pass grpc://grpcservers;
             error_page 502 = /error502grpc;
         }

         location = /error502grpc {
             internal;
             default_type application/grpc;
             add_header grpc-status 14;
             add_header grpc-message "unavailable";
             return 204;
         }
     }
}

  1. h2load works well:
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# ./h2load  -n 1000 -c 50 -d tls.cc http://127.0.0.1:7777/
starting benchmark...
spawning thread #0: 50 total client(s). 1000 total requests
Application protocol: h2c
progress: 10% done
progress: 20% done
progress: 30% done
progress: 40% done
progress: 50% done
progress: 60% done
progress: 70% done
progress: 80% done
progress: 90% done
progress: 100% done

finished in 181.99ms, 5494.75 req/s, 850.50KB/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 154.79KB (158500) total, 93.80KB (96050) headers (space savings 33.76%), 32.23KB (33000) data
					min         max         mean         sd        +/- sd
time for request:     3.78ms     12.20ms      8.83ms      1.33ms    76.40%
time for connect:      158us      1.74ms       895us       437us    62.00%
time to 1st byte:     4.09ms     14.98ms     11.69ms      2.07ms    70.00%
req/s           :     110.49      116.52      112.20        1.22    68.00%
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]#    
  1. So can I say nginx can work as a http/2 reversed proxy? :-)
  2. Also, I found an issue: nginx establishes a dedicated tcp connection to backend server for every HTTP/2 stream:
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# netstat -anp | grep 10.244.0.249 | head -n1
tcp        0      0 10.244.0.252:53382      10.244.0.249:5555       TIME_WAIT   -
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# netstat -anp | grep 10.244.0.249 | wc -l
334
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# netstat -anp | grep 10.244.0.250 | head -n1
tcp        0      0 10.244.0.252:52096      10.244.0.250:5555       TIME_WAIT   -
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# netstat -anp | grep 10.244.0.250 | wc -l
333
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# netstat -anp | grep 10.244.0.251 | head -n1
tcp        0      0 10.244.0.252:48100      10.244.0.251:5555       TIME_WAIT   -
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# netstat -anp | grep 10.244.0.251 | wc -l
333
[root@nghttp2-client-deploy-nginx-8566b9468d-fffgw src]# 

Is it by design or it is caused by bad configuration?
If it is by design, it doesn't leverage http2 benefit to reuse a single tcp connection to transport multiple HTTP/2 streams. Will it be enhanced in the future?

comment:15 by Maxim Dounin, 6 years ago

So can I say nginx can work as a http/2 reversed proxy? :-)

The gRPC proxy module is specifically designed to work with gRPC servers. While it can handle generic HTTP/2 traffic just fine in most cases, I wouldn't recommend using it for generic HTTP/2 proxying - because gRPC is picky/different in various subtle details. For example, gRPC can only work properly if neither request nor response buffering is used, and requires trailer header fields to be passed through, and so on. For general HTTP proxying, consider using the proxy module with HTTP/1.x instead, it is believed to be better option for this task.

If it is by design, it doesn't leverage http2 benefit to reuse a single tcp connection to transport multiple HTTP/2 streams. Will it be enhanced in the future?

As of now, multiplexing different streams in a single upstream connection is not supported. Mostly because of two reasons - a) this is a bad feature from complexity point of view, and b) it is believed to cause more harm than good when talking to backend servers, see comment:1. This is unlikely to change in the near future.

comment:16 by tonyaw@…, 6 years ago

Thanks for your quick reply. So, nginx still doesn't have plan to support a generic HTTP/2 proxy. Right? :-)
In my case, I need a proxy to accept HTTP/2 connection, and forward the HTTP/2 traffic via another HTTP/2 connection to one backend server. So, the proxy module with HTTP/1.x can't meet the requirement. :-(

comment:17 by Maxim Dounin, 4 years ago

See also #1875.

comment:18 by dominic-p@…, 3 years ago

With the advent of HTTP desync attacks (request smuggling), it seems as though this feature could become much more useful. One of the simplest mitigations suggested for these kinds of attacks is to use HTTP/2 for proxied requests:

you can resolve all variants of this vulnerability by configuring the front-end server to exclusively use HTTP/2 to communicate to back-end systems

I realize that the gPRC module is available now, but in light of the comment below, can this issue be reopened to add full HTTP/2 support to proxy_pass?

The gRPC proxy module is specifically designed to work with gRPC servers. While it can handle generic HTTP/2 traffic just fine in most cases, I wouldn't recommend using it for generic HTTP/2 proxying...

in reply to:  18 ; comment:19 by Maxim Dounin, 3 years ago

Replying to dominic-p@…:

With the advent of HTTP desync attacks (request smuggling), it seems as though this feature could become much more useful. One of the simplest mitigations suggested for these kinds of attacks is to use HTTP/2 for proxied requests:

you can resolve all variants of this vulnerability by configuring the front-end server to exclusively use HTTP/2 to communicate to back-end systems

While HTTP/2 might appear to mitigate some of the attacks due to using different framing, it is important to understand that HTTP/2 introduces a wide range of his own vulnerabilities, and these might be worse that the ones you are trying to mitigate by using HTTP/2. Moreover, switching to HTTP/2 is certainly not a solution as long as HTTP/1.x connections remain: there is still possibility of HTTP desync / request smuggling vulnerabilities being present. That is, while switching to HTTP/2 might work in some isolated environments, this is not going to be a large-scale solution.

Further, it is believed that nginx is already good at mitigating HTTP desync / request smuggling attacks, even without using HTTP/2 to backends. In particular because it normalizes Content-Length and Transfer-Encoding while routing requests (and also does not reuse connections to backend servers unless explicitly configured to do so). If there are concerns that such attacks might still be an issue, improving this mitigations might be a better idea, at least from the "large-scale" perspective.

in reply to:  19 comment:20 by dominic-p@…, 3 years ago

Replying to Maxim Dounin:

If there are concerns that such attacks might still be an issue, improving this mitigations might be a better idea, at least from the "large-scale" perspective.

Thanks for the quick, and in-depth reply. I appreciate it. It sounds like nginx is already doing a lot to defeat desync attacks and adding HTTP/2 may not be the best solution. So, it's probably best to leave this closed.

Note: See TracTickets for help on using tickets.