在Nginx当中支持QUIC协议
Quick UDP Internet Connection(QUIC)协议是Google公司提出的基于UDP的高效可靠协议。有关协议的主要内容就不在本文过多描述了,本文主要是来讲一下,在Nginx当中如何去支持QUIC协议。
由于个人水平有限,如果哪里写的不对的地方,还请各位大佬们指正。
环境准备
因为Nginx原生的版本是不带QUIC协议的支持的,因此需要自己编译一下Nginx的源码,加入相关的patch 然后才能够在Nginx当中使用QUIC协议,所以在编译之前,需要一些依赖,本文当中所有的环境不做特殊说明,均基于Ubuntu20.04TLS
当中测试。
因为后面我们用到cloudflare开源的QUIC框架 quiche,该框架基于rust语言开发的,因此我们电脑需要支持rust 环境。
- 配置rust环境
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
- 安装其他相关的依赖
sudo apt-get install build-essential mercurial psmisc lsb-release cmake golang libunwind-dev git libpcre3-dev zlib1g-dev
可选方案
这里,我找到了两个可以让Nginx支持QUIC的方案,不排除还有其他的方案,这里仅介绍如下两个方案:
- 「基于cloudflare的分支版本Nginx」
- 「Nginx官方的Nginx-QUIC项目」
方案过程
基于cloudflare 的分支版本Nginx
首先,我们先来看一下cloudflare开源的quiche方案的版本,为什么要先介绍这个版本呢,因为这个开源的代码当中带有一个简易的QUIC客户端,可以通过这个客户端直接发起QUIC请求,便于我们后面搭建完成之后进行测试。
首先下载quiche的源码
git clone --recursive https://github.com/cloudflare/quiche
下载完成之后,检测一下我们的rust环境是否正常安装,我们运行一下quiche提供的一个访问的例子,后面也同样用这个例子来测试我们搭建的Nginx服务。
cargo run --bin quiche-client -- https://cloudflare-quic.com/
等待一段时间之后,发现如下的运行结果,就代表成功了。
下载Nginx源码
这里需要下载1.16.x
这个版本,通过如下的命令下载并解压Nginx的源码
curl -O https://nginx.org/download/nginx-1.16.1.tar.gz tar xzvf nginx-1.16.1.tar.gz
应用quiche的patch
cd nginx-1.16.1 patch -p01 < ../quiche/nginx/nginx-1.16.patch
添加构建Nginx-QUIC的支持并编译
./configure \ --prefix=$PWD/nginx \ --build="quiche-$(git --git-dir=../quiche/.git rev-parse --short HEAD)" \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_v3_module \ --with-openssl=../quiche/quiche/deps/boringssl \ --with-quiche=../quiche make make install
简单解释一下,上面的参数
—prefix
这里是编译之后安装的位置—build
这个参数是可选的,这个参数在执行-V
命令会显示编译的当前版本的哈希值—with-http_v3_module
这个是支持http3协议—with-openssl
这里编译quic协议需要用到boringssl
所以这里制定用到的ssl的路径—with-quiche
这里是用到quiche这个库
配置完成之后,看到如下的内容,代表这里配置完成了,如果没看到,大概率是哪里有错误,是编译不过的。(我在Mac上没编译过,如果有大佬知道应该怎么处理,欢迎和我交流)
执行编译之后,可能要等待一点点时间,时间不会太长,基本上一分钟以内应该就能搞定了,看到如下的输出,就代表咱们这个编译成功了。
最后执行完make install
之后,就会在我们之前预设的目录看到编译之后的文件了。
运行测试
这里,对于QUIC协议来说,是需要一个证书的,这里我们来偷个懒,直接用quiche里面的测试代码当中的证书,然后我们访问的时候忽略掉证书的验证这样就可以了。如果是正常的使用,大家要去申请ssl证书,并配置域名,这里就是学习,自签名的证书就够了。
- 打开
conf/nginx.conf
进行配置
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=":443"; ma=86400'; } }
这里的配置来自于quiche给出的案例配置,有关其他的详细参数,可以去参考如下的链接:
https://github.com/cloudflare/quiche/blob/master/nginx/README.md
注意: 这里的证书路径需要自己去配置一下成为自己的证书路径。
- 启动Nginx
./sbin/nginx
- 查看一下端口的开放情况
lsof -i:443
- 测试一下是否能够正常访问
cargo run --bin quiche-client -- https://127.0.0.1 --no-verify
这里需要添加—no-verify
这个参数,否则证书校验不过会出现如下的错误:
好了,到这里,我们采用cloudflare开源的quiche方案就介绍完成了,整个过程还是比较顺利的。
「Nginx官方的Nginx-QUIC项目」
下面我们来看一下Nginx官方的方案,采用这个方案,我们需要自己去下载BoringSSL
的源码并编译
下载并编译BoringSSL
git clone https://github.com/google/boringssl.git mkdir build cd build cmake ../ make
这里,这个库用到了golang的环境,如果国内访问速度感人的话,建议某种方式上网或者切换到国内镜像
go env -w GOPROXY=https://goproxy.cn,direct
这里需要稍等一会儿,就编译好了,速度取决于电脑了,编译完成之后的目录结构如下:
编译Nginx-QUIC
wget https://hg.nginx.org/nginx-quic/archive/tip.zip unzip tip.zip cd nginx-quic-55b38514729b ./auto/configure --prefix=$PWD/nginx --with-http_ssl_module --with-http_v2_module --with-http_v3_module --with-cc-opt="-I../boringssl/include" --with-ld-opt="-L../boringssl/build/ssl -L../boringssl/build/crypto" make make install
这里的编译参数和quiche类似,就不在重复赘述了,运行完成之后,我们就可以得到编译之后的Nginx了。
同样的,执行完./configure
之后需要看到如下的内容才算编译成功。
这里最终编译之后的文件和quiche是一样的,然后我们按照同样的方法进行一下测试。
运行测试
这里注意一下,配置文件需要稍微改改, 在conf/nginx.conf
如下所示,具体不同的地方参考注释:
events { worker_connections 1024; } http { server { # Enable QUIC and HTTP/3. 这里和quiche不同,需要设置为http3 listen 443 http3 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=":443"; ma=86400'; } }
依然采用queche的客户端进行一下测试:
到这里,如何让Nginx支持QUIC协议的两种办法就都介绍完成了,至于为什么不用浏览器访问测试呢,原因是因为,如果我关闭掉http2的支持,Chrome就直接没法访问这个地址了,具体原因我也不太清楚,我已经在chrome://flags
当中开启了QUIC的支持,不知道是不是我配置的原因,如果有成功的大佬也欢迎告诉我。