#2502 closed defect (duplicate)

HTTP2 with non SSL causing downgrade to HTTP0.9 for HTTP1.0/HTTP1.1 clients

Reported by: Óscar Vidaković Owned by:
Priority: minor Milestone:
Component: nginx-module Version: 1.22.x
Keywords: http2 http2 Cc:
uname -a: Linux ip-10-130-71-76 5.19.0-1025-aws #26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:03 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux
nginx -V: nginx version: nginx/1.22.1
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-xFgJUM/nginx-1.22.1=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

Description (last modified by Óscar Vidaković)

I have an nginx installation with 2 servers, one listening HTTPS and one listening HTTP, both of them with http2 enabled in the listen directive. The HTTP server is quite simple and it's just used by an AWS ALB to perform healthchecks:

server {

listen 81 http2 default_server;
access_log off;
location /ping {

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;



The HTTPS is working just fine, but I cannot stablish successful connections to the HTTP server with non HTTP2 capable clients:

$ curl -v --http1.1

  • Trying
  • Connected to ( port 81 (#0)

    GET / HTTP/1.1
    User-Agent: curl/7.81.0
    Accept: */*

  • Received HTTP/0.9 when not allowed
  • Closing connection 0

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

As you can see, even forcing curl to send HTTP1.1 headers, nginx is downgrading it to HTTP0.9, causing curl to reject the protocol and disconecting. Performing the same test in https works fine:

$ curl -o test -k -v --http1.1

  • Trying

Connected to ( port 443 (#0)

  • ALPN, offering http/1.1
  • SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
  • ALPN, server accepted to use http/1.1
  • Server certificate:
  • subject: [NONE]
  • start date: May 22 13:02:37 2023 GMT
  • expire date: May 19 13:02:37 2033 GMT
  • Server auth using Basic with user 'xxx'

    GET / HTTP/1.1
    Authorization: Basic <redacted>
    User-Agent: curl/7.81.0
    Accept: */*

  • Mark bundle as not supporting multiuse

< HTTP/1.1 200 OK
< Server: nginx
< Date: Tue, 30 May 2023 11:53:48 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: <redacted>
< Set-Cookie: <redacted>

As far as I understand, as long as the client is sending a HTTP protocol header, nginx should honour this header and try to serve this protocol instead of forcing to use the oldest one, specially when it's a protocol from begining 90s which now is considered ineficient.Also this is the behaviour being observed in HTTPS connections. The current behaviours leaves the HTTP servers with HTTP2 enabled in an almost non-funciontal state as most of the HTTP clients doesn't support HTTP0.9. For example AWS ALB is not capable to perform the healthchecks, curl is not working, nor wget, etc.

Change History (2)

comment:1 by Óscar Vidaković, 11 months ago

Description: modified (diff)

comment:2 by Maxim Dounin, 11 months ago

Resolution: duplicate
Status: newclosed


listen 81 http2 default_server;

line in your configuration configures the listening socket on port 81 to use HTTP/2 with prior knowledge, see here. Attempts to use it with anything but HTTP/2 are rejected with appropriate HTTP/2 error.

If you want to use such socket in curl, consider curl --http2-prior-knowledge.

Duplicate of #808.

Note: See TracTickets for help on using tickets.