Zxilly
Try to be 1%
Zxilly's Blog
如何为 Nginx 配置 QUIC

因为这篇文章实在拖了太久,所以 Nginx 已经有官方实现了,详情请参见 https://quic.nginx.org/,但是这个实现是 IETF QUIC,如果你想要兼容 gQUIC,请继续阅读

起因

什么是 QUIC?

快速 UDP 网络连接(英语:Quick UDP Internet Connections,缩写:QUIC)是一种实验性的网络传输协议。由 Google 开发,在 2013 年实现。QUIC 使用 UDP 协议。 2015 年 6 月,QUIC 的网络草案被正式提交至互联网工程任务组。2018 年 10 月,互联网工程任务组 HTTP 及 QUIC 工作小组正式将基于 QUIC 协议的 HTTP(英语:HTTP over QUIC)重命名为 HTTP/3 以为确立下一代规范做准备。

我为什么应该使用 QUIC?

理论上

QUIC 旨在提供几乎等同于 TCP 连接的可靠性,但延迟大大减少。QUIC 的另一个目标是提高网络切换期间的性能。

实际上

对于个人开发者而言,QUIC 带来的提升其实并不明显 而且由于国内的网络环境,UDP 包的 QoS 级别比 TCP 更低,很容易在网关处丢包,体验反而不如 http/2 但是用上新技术本身就是目的)

操作

选择

个人用户的选择并不多,在不考虑自行开发的情况下,可供选择的只有 cloudflare 开源的 QUICHE, 或者使用 caddy 作为反向代理单独监听 UDP/443,但是这些实现基本都是 IETF QUIC。 也就是说,市场主流的 chrome 及 chromium 浏览器如果要使用 QUIC 连接的话,需要在启动项中单独添加参数,对用户并不友好。谷歌系目前默认启用的还是 gQUIC,即谷歌自己的实现。 我找来找去,找到一个由搜狐开源的 patch。

准备源码

你需要一个可以运行的 Linux 实例,保留 50G 以上的磁盘空间,推荐使用 Ubuntu 18.04LTS

nginx-quic 部分

git clone https://github.com/evansun922/nginx-quic.git

chromium 部分

获取 chromium 源码

因为这个 patch 是基于 chromium 的,需要获取 chromium 的源码

警告
由于国内的特殊网络环境,这可能是最难的一步,请仔细阅读。

谷歌实在是太有钱了,所以几乎什么东西都自己做了一个, 我们需要使用 depot_tools 来下载源码。

git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=/path/to/depot_tools:$PATH

接下来,使用

fetch chromium

来获取源码,注意,fetch 命令不支持断点续传,而且 chromium 体积约为 22G,最好确认自己有一个稳定的科学环境再开始下载 当 fetch 执行完成之后,你的工作目录里应当有

.gclient   # A configuration file for you source checkout
src/       # Top-level Chromium source checkout.

执行

cd src && ./build/install-build-deps.sh

来安装必要的依赖,完成这几步后

gclient sync

来完成相应的 hooks

检出对应版本源码

请检查 nginx-quic 的最新 commit,来确定自己应当使用的 chromium 版本。 比如,对于 comiitd117af2,我们可以得知对应的 chromium 版本为 86.0.4224.0 进入 src 目录,运行

git checkout 86.0.4224.0

来检出对应版本,随后运行

gclient sync -D

来完成 hooks。

nginx 部分

http://nginx.org/en/download.html 下载源码并解压即可

编译

进入 nginx-quic 目录,运行

python3 mk2gn.py </path/to/nginx> </path/to/chromium/src> <args>

</path/to/nginx>:         nginx 源码根目录路径。
</path/to/chromium/src>:          chromium 源码 src 目录路径。
< args>:          configure nginx 时,所需的参数。

这里放上我的参数以作参考

python3 mk2gn.py "/home/zxilly/Downloads/nginx-1.19.2" \
"/home/zxilly/quic/quic/src" "--user=www --group=www \
--prefix=/www/server/nginx \
--add-module=/www/server/nginx/src/ngx_devel_kit \
--add-module=/www/server/nginx/src/lua_nginx_module \
--add-module=/www/server/nginx/src/ngx_cache_purge \
--add-module=/www/server/nginx/src/nginx-sticky-module \
--with-pcre=pcre-8.43 \
--with-http_v2_module \
--with-stream --with-stream_ssl_module --with-stream_ssl_preread_module \
--with-http_stub_status_module \
--with-http_ssl_module --with-http_image_filter_module \
--with-http_gzip_static_module \
--with-http_gunzip_module \
--with-http_sub_module \
--with-http_flv_module \
--with-http_addition_module \
--with-http_realip_module \
--with-http_mp4_module \
--with-ld-opt=-Wl,-E \
--with-cc-opt=-Wno-error \
--with-ld-opt=-ljemalloc \
--with-http_dav_module \
--add-module=/www/server/nginx/src/nginx-dav-ext-module \
--add-module=/root/ngx_brotli"

切换到 chromium 的 src 目录,执行

gn gen out/Release --args="is_component_build=false is_debug=false"

这时可以在 net/BUILD.gn 文件中添加 nginx 编译需要的库文件和动态链接

如果直接添加库路径编译出错,可以把需要的头文件单独软链接到其他目录

executable("nginx") {
sources = [
# 所用到的.c 或者.cc 源码,一般不用修改
]
include_dirs = [
#头文件 dir,类似与 "-I"
]
lib_dirs = [
#  库的搜索目录,类似与-L your libdir
]
libs = [
# dynamic library: pthread or static library: /path/xxx.a
]
cflags_c = [
# 编译选项
"-D_FORTIFY_SOURCE=2",
"-DTCP_FASTOPEN=23",
"-DNDK_SET_VAR",
]
}

执行 ninja -C out/Release nginx,编译好的 nginx-quic 就在 out/Release 目录中。

执行./nginx -V 来检查编译是否成功

file

demo

如果你确定能够满足这些条件

file

那么你可能可以直接使用我编译好的 nginx 文件

nginx

配置文件

请参照 nginx-quic 文档关于 Alt-Svc 头部,提供一个参考

add_header alt-svc 'quic=":443";ma=500;v="50,48,47,46,44,43,39";h3-29=":443";ma=2592000;h3-28=":443";ma=2592000;h3-27=":443";ma=2592000;h3-25=":443";ma=2592000;h3-24=":443";ma=2592000;';

参考

[1] nginx-quic[2] depot_tools_turtorial

learningman

文章作者

发表评论

textsms
account_circle
email

Zxilly's Blog

如何为 Nginx 配置 QUIC
为Nginx配置兼容gQUIC的http/3实现
扫描二维码继续阅读
2020-08-15