Is it possible to run HTTP/2 on NGINX port 443 without ssl?
Asked Answered
S

2

8

I have Envoy Proxy handling SSL termination. Nginx (1.17.0 in a docker container, compiled --with-http_v2_module) is one of several upstream services. As a result, Nginx receives traffic on port 443 but does not use the ssl module:

server {
    listen 443;
    server_name example.com www.example.com;
    root /var/www/html;

...

This works fine, but if I try to add http2 to the end of the listen line I receive:

curl: (1) Received HTTP/0.9 when not allowed

... not just for example.com in question, but all servers.

I would like Envoy to speak with Nginx via HTTP/2 for obvious performance reasons.

Is there some trick to make nginx use http2 on port 443 without SSL termination?


Edit:

The core nginx.conf:

user  nginx;
worker_processes  2;

pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    client_max_body_size 64M;

    sendfile        on;

    keepalive_timeout  65;

    fastcgi_cache_path /etc/nginx-cache levels=1:2 keys_zone=multipress:100m inactive=60m;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";
    fastcgi_cache_use_stale error timeout invalid_header http_500;
    fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

    gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

Note that I can successfully curl the current Envoy HTTP2 server with an explicit curl --http2 command. The problem is the HTTP2 connection between Envoy and Nginx.

Sopping answered 13/5, 2020 at 18:45 Comment(2)
Can you show the curl command you are using?Limburger
@BarryPollard this was actually the error returned from Kubernetes' healthcheck, as well. But I simply did a "curl localhost:443" from inside the docker container. Of course my curl version supports http2, and I have tested it on http/2 servers. In fact, it works when I curl the same resource using the current Envoy (http2) -> nginx (http1) path.Sopping
L
12

Nginx only supports h2c (which is what HTTP/2 without HTTPS is called), so you can not connect using HTTP/1.1 and then upgrade.

In fact if you try to connect using HTTP/1.1 then nginx will error as it doesn’t support HTTP/1.1 and HTTP/2 on the same port unless you are using HTTPS.

So for curl you have to use this syntax to jump straight into HTTP/2:

curl --http2-prior-knowledge localhost:80

Not sure if there is a similar config in Envoy as don’t use that but if the above works with curl and still get same error with Envoy then at least you’ve got the answer to your Nginx question.

However I’m not at all sure it’s necessary or even wise to enable h2c for your back end server. For a start that disables HTTP/1.1 as discussed above and any other applications, services, or even curl test commands that use HTTP/1.1 will break.

In addition the benefits of HTTP/2 at the back end are questionable, and the main benefit is for client to server connections rather than server to server back end connections.

Limburger answered 13/5, 2020 at 21:7 Comment(1)
Excellent, very thorough — and I didn't realize that about the HTTP/2 backend. I'll just give up on the idea then :)Sopping
C
1

Include "http2" right after the listen port in /etc/nginx/nginx.conf as below and restart nginx pid (service nginx restart)

server {
    listen 80 http2;
    server_name  myhost.mydomain.com;

location ^~ /api/detection/ {
    include uwsgi_params;
    proxy_pass    http://models;
}
Cheroot answered 26/11, 2021 at 11:1 Comment(3)
Here it made nginx to return a broken return. The status is 200 with a message: HTTP/1.0 200 This buggy server did not return headersNormy
This does not address the question at all — which has to do with port 443 in particular, as the title says.Sopping
This was exactly my problem. One of my site configs had listen 80 http2; and changing to listen 80; fixed it. Strange that this broken setting on another site config broke my default site.Adipocere

© 2022 - 2024 — McMap. All rights reserved.