Zxilly
Calm down
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

# # # # #
首页      代码      如何为Nginx配置QUIC

Zxilly

文章作者

发表回复

textsms
account_circle
email

  • 执行 ninja -C out/Release nginx 提示这个,
    root@quic:~/chromium/src# ninja -C out/Release nginx
    ninja: Entering directory `out/Release’
    ninja: error: unknown target ‘nginx’, did you mean ‘gin’?
    请问这是什么问题造成的啊?

    4 年前 回复
    • @佩佩: 发现预编译nginx 时最后一行就报错了,
      open “objs/Makefile” failed, string index out of range
      是关于 Python 执行的报错。
      不知道该怎么办了。。。

      4 年前 回复
      • learningman博主

        @佩佩: 你是不是用了python2?

        4 年前 回复
        • @learningman: python2.7和 Python3.8 都有安装

          4 年前
        • learningman博主

          @佩佩: 我需要更多信息才能判断,你把编译用的命令啥的发我邮箱吧

          4 年前
    • learningman博主

      @佩佩: 这个是因为你还没执行那个patch脚本

      4 年前 回复

Zxilly's Blog

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