Please use this template for troubleshooting questions.
My issue:
By default, proxy_params sent $http_host to proxy servers and not $host. However only HTTP/1 and HTTP/1.1 is available as proxy_pass.
How I encountered the problem:
If you use HTTP/3 in NGINX, there is no more Host: header in the request, as it is dealed during the TLS handshake. Therefore, proxies does not get Host: header which is however a requirement of HTTP/1.1 and reject with a 400 header Bad request without any logs.
Solutions I’ve tried:
The use by default of $host in proxy_params would solve or a specific param to set it only for HTTP/3.
Version of NGINX or NGINX adjacent software (e.g. NGINX Gateway Fabric): Nginx Debian 1.28.0
Your overall assessment is correct, but I am not entirely sure what you mean by proxy_params. Is that a file contained in your NGINX installation? If so, could you share the contents of the file and let us know where did you install NGINX from? There might be nothing we can tweak on our end to solve this issue
Changing $http_host to $host solves the problem. I think @liam solution could work as well, but maybe is more or less the same as $host. My question is also: why it is not implemented by default as nginx provides HTTP/3 on stable?
An unchanged “Host” request header field can be passed like this: proxy_set_header Host $http_host;
However, if this field is not present in a client request header then nothing will be passed. In such a case it is better to use the $host variable - its value equals the server name in the “Host” request header field or the primary server name if this field is not present: proxy_set_header Host $host;