如何找出为什么 Nginx return 400 而将其用作 http/2 负载均衡器?
How to find out why Nginx return 400 while use it as http/2 load balancer?
我正在自己实施一个 http/2 代理,我正在使用 Nginx 作为负载平衡器。
当我使用 Nginx 作为 h2c 负载平衡器时,它有效:
server {
listen 8443 http2;
location / {
error_log /Users/jiajun/nginx_error_log.log debug;
grpc_pass grpc://127.0.0.1:2017;
}
}
运行它:
$ go run example/grpc_client/main.go
calling to 127.0.0.1:2019
2019/01/28 11:50:46 gonna call c.SayHello...
2019/01/28 11:50:46 Greeting: Hello world
而Nginx访问日志为:
127.0.0.1 - - [28/Jan/2019:11:50:46 +0800] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" "grpc-go/1.16.0" "-"
但是当我在 SSL 下提供它时它不起作用:
server {
listen 8443 ssl http2;
ssl_certificate /Users/jiajun/127.0.0.1.crt;
ssl_certificate_key /Users/jiajun/127.0.0.1.key;
location / {
error_log /Users/jiajun/nginx_error_log.log debug;
grpc_pass grpc://127.0.0.1:2017;
}
}
运行它:
$ go run example/grpc_client/main.go
calling to 127.0.0.1:2019
2019/01/28 11:53:06 gonna call c.SayHello...
2019/01/28 11:53:06 could not greet: rpc error: code = Unavailable desc = transport is closing
exit status 1
并且,Nginx访问日志为:
127.0.0.1 - - [28/Jan/2019:11:53:06 +0800] "PRI * HTTP/2.0" 400 157 "-" "-" "-"
所以我想找出为什么在我使用 SSL 时它 return 是 400。但是 Nginx 不会在错误日志中记录该过程,即使我将日志级别设置为调试(并且它已使用 --with-debug
选项编译)。
有什么调试的好办法吗?
看起来 Nginx 不认为它在说话 HTTP/2 因为 go 客户端正在发送连接序言消息 ("PRI * HTTP/2.0"
),Nginx 认为这是一个真实的消息。
可能的问题是 Nginx 没有在 SSL/TLS 握手中声明它支持 HTTP/2 通过 ALPN(或旧的 NPN)。 Nginx 是用哪个版本的 OpenSSL(或同等版本)构建的? 运行 nginx -V
看到这个。理想情况下,您希望 1.0.2 或更高版本支持 ALPN。
同时检查您的 SSL/TLS 密码是否未使用 one of the ciphers forbidden for HTTP/2. Config like below (generated by the Mozilla SSL config generator) 应确保首选正确的密码:
# modern configuration. tweak to your needs.
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
我正在自己实施一个 http/2 代理,我正在使用 Nginx 作为负载平衡器。
当我使用 Nginx 作为 h2c 负载平衡器时,它有效:
server {
listen 8443 http2;
location / {
error_log /Users/jiajun/nginx_error_log.log debug;
grpc_pass grpc://127.0.0.1:2017;
}
}
运行它:
$ go run example/grpc_client/main.go
calling to 127.0.0.1:2019
2019/01/28 11:50:46 gonna call c.SayHello...
2019/01/28 11:50:46 Greeting: Hello world
而Nginx访问日志为:
127.0.0.1 - - [28/Jan/2019:11:50:46 +0800] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" "grpc-go/1.16.0" "-"
但是当我在 SSL 下提供它时它不起作用:
server {
listen 8443 ssl http2;
ssl_certificate /Users/jiajun/127.0.0.1.crt;
ssl_certificate_key /Users/jiajun/127.0.0.1.key;
location / {
error_log /Users/jiajun/nginx_error_log.log debug;
grpc_pass grpc://127.0.0.1:2017;
}
}
运行它:
$ go run example/grpc_client/main.go
calling to 127.0.0.1:2019
2019/01/28 11:53:06 gonna call c.SayHello...
2019/01/28 11:53:06 could not greet: rpc error: code = Unavailable desc = transport is closing
exit status 1
并且,Nginx访问日志为:
127.0.0.1 - - [28/Jan/2019:11:53:06 +0800] "PRI * HTTP/2.0" 400 157 "-" "-" "-"
所以我想找出为什么在我使用 SSL 时它 return 是 400。但是 Nginx 不会在错误日志中记录该过程,即使我将日志级别设置为调试(并且它已使用 --with-debug
选项编译)。
有什么调试的好办法吗?
看起来 Nginx 不认为它在说话 HTTP/2 因为 go 客户端正在发送连接序言消息 ("PRI * HTTP/2.0"
),Nginx 认为这是一个真实的消息。
可能的问题是 Nginx 没有在 SSL/TLS 握手中声明它支持 HTTP/2 通过 ALPN(或旧的 NPN)。 Nginx 是用哪个版本的 OpenSSL(或同等版本)构建的? 运行 nginx -V
看到这个。理想情况下,您希望 1.0.2 或更高版本支持 ALPN。
同时检查您的 SSL/TLS 密码是否未使用 one of the ciphers forbidden for HTTP/2. Config like below (generated by the Mozilla SSL config generator) 应确保首选正确的密码:
# modern configuration. tweak to your needs.
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;