无法在反向代理上使用 nginx 1.25.3 设置 HTTP3/QUIC

无法在反向代理上使用 nginx 1.25.3 设置 HTTP3/QUIC

现在nginx 支持 QUIC 和 HTTP/3从 1.25.0 开始,我就想尝试一下。我使用 boressl 编译了相同的内容,如下所示:

wget https://nginx.org/download/nginx-1.25.3.tar.gz

tar xzf nginx-1.25.3.tar.gz

cd /opt
git clone https://boringssl.googlesource.com/boringssl
cd /opt/boringssl
cmake -GNinja -B build
ninja -C build

cd /opt/nginx-1.25.3/
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock \
    --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
    --user=nginx --group=nginx --with-compat --with-file-aio --with-threads \
    --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module \
    --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module \
    --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module \
    --with-http_sub_module --with-http_v2_module --with-http_v3_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module \
    --with-cc-opt='-g -O2 -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC -I../boringssl/include' \
    --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie -L../boringssl/build/ssl -L../boringssl/build/crypto'
make && make install

这确实使用 BoringSSL 编译 nginx:

# nginx -V
nginx version: nginx/1.25.3
built by gcc 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) 
built with OpenSSL 1.1.1 (compatible; BoringSSL) (running with BoringSSL)
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_v3_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC -I../boringssl/include' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie -L../boringssl/build/ssl -L../boringssl/build/crypto'

然后,我对 quic/http 服务器进行了以下配置:

server {
    listen 443 ssl default_server;
    # listen [::]:443 ssl reuseport;
    listen [::]:443 quic default_server reuseport;
    # listen [::]:443 quic reuseport;
    http2 on;
    http3 on;
    http3_hq on;
    quic_retry on;
    
    # SSL configuration
    ssl_certificate         /etc/ssl/lp-playback.studio/fullchain;
    ssl_certificate_key     /etc/ssl/lp-playback.studio/key;
    ssl_protocols       TLSv1.3;
    # ssl_client_certificate /etc/ssl/cloudflare.crt;
    # ssl_verify_client on;
    ssl_early_data on;
    ssl_stapling on;
    ssl_stapling_verify on;

    server_name bgw-2.lp-playback.studio;

    #root /var/non-existing-path-just-testing;
    #index index.html index.htm index.nginx-debian.html;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_buffering off;
    proxy_http_version 1.1;
    proxy_read_timeout 600s;
    # add_header Alt-Svc 'quic=":$server_port"; ma=2592000; v="46,43,39"';    
    add_header Alt-Svc 'h3=":$server_port"; ma=86400' always;
    add_header quic-status $http3 always;
    add_header x-quic 'h3' always;

    location / {
        proxy_pass http://localhost:8080;
    }
}

TLS 证书是使用acme.sh 客户端。但是,当尝试使用支持 http3 的 curl 进行验证时,它返回的是 http2 连接:

➜ docker run --rm ymuski/curl-http3 curl -I -X GET --http3 'https://bgw-2.lp-playback.studio/'                                                                             (master⇂1|♽1…35⚑2)
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0   185    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
HTTP/2 415 
date: Fri, 24 Nov 2023 08:18:50 GMT
content-length: 185
access-control-allow-credentials: true
access-control-allow-headers: *
access-control-allow-methods: GET, POST, OPTIONS, HEAD
access-control-allow-origin: *
access-control-expose-headers: *
access-control-max-age: 600
access-control-request-headers: *
access-control-request-method: GET
cache-control: no-cache, no-store, must-revalidate
expires: 0
pragma: no-cache
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
content-security-policy: object-src 'none'; frame-ancestors 'self'; form-action 'self'; block-all-mixed-content; sandbox allow-forms allow-same-origin allow-scripts allow-popups allow-downloads; base-uri 'self';
alt-svc: h3=":443"; ma=86400
x-quic: h3
access-control-allow-origin: *
timing-allow-origin: *
access-control-allow-methods: GET,POST,OPTIONS,PUT,DELETE
access-control-allow-credentials: true
access-control-allow-headers: Origin,Content-Type,Accept,Authorization,X-Packet-Service-Type,X-Packet-URI,X-User-Address,XD-User-Address,X-Request-From,X-Response-Format
access-control-max-age: 1728000

我现在很困惑为什么 http3 连接根本没有建立。如果我收到详细的 curl 请求,我会看到以下内容被记录:

*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
*   Trying 34.18.75.164:443...
* Connected to bgw-2.lp-playback.studio (34.18.75.164) port 443
* ALPN: offers h2,http/1.1
} [5 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
.
.

ALPN 似乎只支持 h2 和 http1.1?我在编译 nginx 时是否遗漏了什么?nginx-conf 中的 http/server 块是否配置错误?nginx 是否不支持 h3 反向代理(这很奇怪)?

欢迎任何相关建议。

答案1

这是 nginx 配置的问题,具体如下:

server {
    listen 443 ssl default_server;
    listen [::]:443 quic default_server reuseport;

quic 协议已配置为在 IPv6 上监听([::]:443)!

将其更改为以下内容:

server {
    listen 443 ssl default_server;
    listen 443 quic default_server reuseport;

有效。该域名现在正在使用 http3:

➜ docker run --rm ymuski/curl-http3 curl -I -X GET --http3 'https://bgw-2.lp-playback.studio/'
HTTP/3 415 
server: nginx/1.25.3
date: Mon, 27 Nov 2023 03:42:47 GMT
content-length: 185
access-control-allow-credentials: true
access-control-allow-headers: *
access-control-allow-methods: GET, POST, OPTIONS, HEAD
access-control-allow-origin: *
access-control-expose-headers: *
access-control-max-age: 600
access-control-request-headers: *
access-control-request-method: GET
cache-control: no-cache, no-store, must-revalidate
expires: 0
pragma: no-cache
alt-svc: h3=":443"; ma=86400
quic-status: h3
x-quic: h3

相关内容