NGINX 的 HTTP/3 尝试

2019 年 9 月 26 日,Cloudflare 正式启用了 HTTP/3,详情见 HTTP/3: the past, the present, and the future。随后 10 月 17 日 Cloudflare 放出了基于 quiche 项目 的 NGINX patch,详情见 Experiment with HTTP/3 using NGINX and quiche。也正是这个 Patch 才会有这篇水文,而关于 HTTP/3 的介绍不再赘述,有兴趣的可以去 HTTP / 3:从头到脚的介绍 看看。

安装

参照
给 NGINX 添加 TLSv1.3 支持
准备除 OpenSSL 相关的依赖(OpenSSL 本体和三个 patch)
注意:同时打 HTTP/3 patch 和 hakasenyang 的 HPACK patch 需要手动解决冲突 (auto/options 文件),或者可以先打 HTTP/3 patch 然后再打 我修改过的 HPACK patch

另外虽然 Cloudflare 的文章里说该 patch 只在 NGINX 1.16.x 可用,但实测 1.17.x 也没什么问题。

Note that the HTTP/3 and QUIC patch only works with the 1.16.x release branch (the latest stable release being 1.16.1).

quiche

1
2
3
git clone --recursive https://github.com/cloudflare/quiche
cd nginx-1.17.6
patch -p1 < ../quiche/extras/nginx/nginx-1.16.patch

P.s. 指定 commit 的原因是最近 Cloudflare 的几个提交添加了 h3-24 草案的支持,但会导致浏览器端的 h3-23 无法正常使用以及 http3check.net 的测试结果不正常。 最新 commit 修好了。

编译

configure 配置参照
给 NGINX 添加 TLSv1.3 支持
去除 --with-cc-opt--with-ld-opt 以及 --with-openssl-opt 部分。然后添加以下参数,最后照常编译、测试、安装到系统。

1
2
3
4
--build="quiche-$(git --git-dir=../quiche/.git rev-parse --short HEAD)" \
--with-http_v3_module \
--with-openssl=../quiche/deps/boringssl \
--with-quiche=../quiche

配置 NGINX

确保 ssl_protocols 包含 TLSv1.3,然后将 quicreuseport 选项添加到单独的 listen 配置里,并添加对应的 alt-svc 头。
注意:有多个站点时 reuseport 参数只需要添加一次,否则 NGINX 会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
events {
worker_connections 1024;
}

http {
server {
# Enable QUIC and HTTP/3.
listen 443 quic reuseport;

# Enable HTTP/2 (optional).
listen 443 ssl http2;

ssl_certificate cert.crt;
ssl_certificate_key cert.key;

# Enable all TLS versions (TLSv1.3 is required for QUIC).
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

# Add Alt-Svc header to negotiate HTTP/3.
add_header alt-svc 'h3-27=":443"; ma=86400, h3-25=":443"; ma=86400, h3-24=":443"; ma=86400, h3-23=":443"; ma=86400';
}
}

客户端测试

浏览器

查看 HTTP/3 支持表:Can I use…

由此表可知 Firefox 需要 72+ 并在 about:config 内 打开 network.http.http3.enabled 而 Chrome 需要 79+ 并自行添加 --enable-quic(这个参数如果已经使用 flags 开启了则可忽略)和 --quic-version=h3-23 启动命令,我这里使用 Microsoft Edge 稳定版演示。
edge-command

添加完参数后,打开支持 HTTP/3 (h3-23) 的站点,使用开发者工具的网络功能可以看到如果 HTTP/3 成功连接,协议会显示为 http/2+quic/99(暂时)
edge-developer-tools-network

curl

拉取 quiche 和 BoringSSL

1
git clone --recursive https://github.com/cloudflare/quiche

编译 BoringSSL

1
2
3
4
5
6
7
8
9
cd quiche/deps/boringssl
mkdir build
cd build
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=on ..
make
cd ..
mkdir -p .openssl/lib
cp build/crypto/libcrypto.a build/ssl/libssl.a .openssl/lib
ln -s $PWD/include .openssl

编译 quiche

1
2
cd ../..
QUICHE_BSSL_PATH=$PWD/deps/boringssl cargo build --release --features pkg-config-meta

拉取并编译 curl

1
2
3
4
5
6
7
cd ..
git clone https://github.com/curl/curl
cd curl
./buildconf
./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-ssl=$PWD/../quiche/deps/boringssl/.openssl --with-quiche=$PWD/../quiche/target/release --with-libssh2 --enable-alt-svc --with-librtmp --enable-tls-srp --with-gssapi --enable-doh
make
sudo make install

测试

1
2
3
4
5
6
7
8
9
10
11
 π curl master ❯ /usr/local/bin/curl -I --http3 https://love4taylor.com
HTTP/3 200
server: nginx/1.17.6
date: Wed, 04 Dec 2019 03:08:01 GMT
content-type: text/html
content-length: 10740
vary: Accept-Encoding
etag: "5de3d7e3-29f4"
strict-transport-security: max-age=31536000; includeSubDomains; preload
alt-svc: h3-23=":443"; ma=86400
accept-ranges: bytes

curl-http3