本文主要介绍使用nginx-quic和boringssl项目来对服务器进行升级支持HTTP/3协议。
1、背景介绍
nginx官方从1.19版本开始,新建立了一个分支,专门用来对QUIC进行支持,官网的链接点这里。注意该项目还处于早期的alpha版本,非常不建议用于生产环境。
The code is at an early alpha level of quality and should not be used in production.
nginx-quic的安装包可以在下面这里找到,由于还处于开发阶段,项目更新得非常快。
https://hg.nginx.org/nginx-quic/shortlog/quic
从官网的readme文件我们可以了解到,截止到2020年8月21日,nginx-quic项目目前只支持h3-27
、h3-28
、h3-29
三个版本,再早期的草案版本并不支持,不过目前更新的速度非常快,变动也很大。
Currently we support IETF-QUIC draft-27, draft-28, draft-29.
Earlier drafts are NOT supported as they have incompatible wire format.
考虑到浏览器的兼容性,接下来我们主要基于h3-27版本进行测试。
同时需要注意的是openssl官方版本目前并不支持quic协议,官方于2020年2月给出的原因是目前quic并不稳定,还有很多版本需要迭代确定,它们需要优先把精力放在openssl3.0版本的开发上,等到openssl3.0版本开发完成了再来进行quic的支持。
So in conclusion; QUIC is on our minds, but it will not be included in the OpenSSL 3.0 release. We expect more tangible action to happen after we’ve released OpenSSL 3.0.
所以我们这里需要用到谷歌自己使用的openssl分支版本boringssl,这是谷歌对应的开源的自用的openssl版本,谷歌官方表示boringssl这个项目虽然开源了,但是并不建议大家在生产环境上广泛使用,因为它是根据谷歌自身的需求进行调整的,有些API可能并不稳定。
后续更新:2021年5月份,RFC 9000正式发布了HTTP3-QUIC。
2、编译安装nginx-quic
这里我们使用了CentOS7来进行编译安装
# lsb_release -a LSB Version: :core-4.1-amd64:core-4.1-noarch Description: CentOS Linux release 7.9.2009 (Core) Release: 7.9.2009 Codename: Core
首先我们在系统中使用yum安装基本的编译工具,注意此次使用的很多软件工具和依赖都是需要较新版本的,因此后面会进行大量的编译安装,请确保机器拥有足够的性能(可能需要编译gcc)和良好的网络。主要需要使用到的工具软件的安装步骤如下:
2.1 yum安装依赖
需要注意的是这里安装所需要的软件很多,这里并不能全部列出来,但是除了列出来的软件对新版本有要求外,别的都可以直接使用yum进行安装,当然也可以自己根据需要编译安装新版本。后面根据需求自己安装
2.2 编译安装cmake
cmake的版本必须要在3.0以上,cmake可以到这里下载https://cmake.org/download/
。
wget https://github.com/Kitware/CMake/releases/download/v3.18.2/cmake-3.18.2.tar.gz tar -zxvf cmake-3.18.2.tar.gz ./bootstrap gmake make make install cmake --version
2.3 编译安装perl
perl的安装包可以从这里www.cpan.org/src
下载。perl的版本需要尽可能新,否则可能会出现问题,这里使用的是5.32.0的稳定版本(截止2020-08-21)
wget https://www.cpan.org/src/5.0/perl-5.32.0.tar.gz tar -zxvf perl-5.32.0.tar.gz cd perl-5.32.0/ ./Configure -des -Dprefix=/usr/local/perl make -j8 make test make install # 注意最后检查一下系统默认的perl是否为我们新安装的perl perl -v # 如果不是则需要进行修改 # 查看默认的perl which perl | xargs file # 替换新安装的perl和原来的perl mv /usr/bin/perl /usr/bin/perl.5.16.3 # 需要注意新安装的perl目录要根据前面编译的时候指定的目录来确定 ln -s /usr/local/perl/bin/perl /usr/bin/perl # 再次检查 perl -v
2.4 安装golang
golang的安装配置比较简单,我们从https://golang.org/dl
直接下载最新的稳定版本即可。
wget https://golang.org/dl/go1.15.linux-amd64.tar.gz tar -zxvf go1.15.linux-amd64.tar.gz -C /usr/local # 修改系统默认的go文件 ln -s /usr/local/go/bin/go /usr/bin/go
接下来的go环境变量同学们可以根据自己的实际需求进行配置。对于我个人而言,我直接在/etc/profile
中添加下面的配置然后source生效即可。
export GOROOT=/usr/local/go export GOBIN=$GOROOT/bin export PATH=$PATH:$GOBIN export GOPATH=/home/gopath
2.5 编译安装gcc
CentOS7默认的gcc的版本太旧了,编译boringssl的时候会报错,我们手动编译安装新版本的gcc,这里使用的是10.2.0的版本。gcc的版本可以在这里下载http://ftp.gnu.org/gnu/gcc/
。
wget http://ftp.gnu.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.gz tar -zxvf gcc-10.2.0.tar.gz cd gcc-10.2.0/ # 解压完成后需要下载四个依赖,我们执行脚本即可直接下载,服务器网络不好的同学也可以手动下载 ./contrib/download_prerequisites # 这里需要对c和c++进行支持,为了节省时间禁用掉了交叉编译 ./configure -enable-checking=release -enable-languages=c,c++ -disable-multilib # 接下来这里需要很久 make -j8 make install # 安装完成之后我们需要替换原来的cc文件和c++文件,确保它们的版本都是最新的版本 # 一般来说原来系统的cc文件和c++文件都在/usr/bin/目录下,而我们编译安装的cc文件和c++文件在/usr/local/bin/ cd /usr/bin/ mv /usr/bin/cc /usr/bin/cc.4.8.5 mv /usr/bin/c++ /usr/bin/c++.4.8.5 ln -s /usr/local/bin/gcc /usr/bin/cc ln -s /usr/local/bin/c++ /usr/bin/c++ # 最后检查版本 /usr/bin/cc -v /usr/bin/c++ -v
gcc下载的依赖内容如下,有需要的同学自取
# ./contrib/download_prerequisites 2020-08-21 21:28:24 URL:http://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840/2383840] -> "./gmp-6.1.0.tar.bz2" [1] 2020-08-21 21:28:26 URL:http://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284/1279284] -> "./mpfr-3.1.4.tar.bz2" [1] 2020-08-21 21:28:28 URL:http://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925/669925] -> "./mpc-1.0.3.tar.gz" [1] 2020-08-21 21:28:30 URL:http://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 [1658291/1658291] -> "./isl-0.18.tar.bz2" [1] gmp-6.1.0.tar.bz2: OK mpfr-3.1.4.tar.bz2: OK mpc-1.0.3.tar.gz: OK isl-0.18.tar.bz2: OK All prerequisites downloaded successfully.
2.6 编译安装boringssl
谷歌官方建议我们使用ninja
来编译安装boringssl,因此我们需要先安装一个ninja
。
wget https://github.com/ninja-build/ninja/releases/download/v1.10.2/ninja-linux.zip unzip ninja-linux.zip cp -r ninja /usr/bin/ which ninja # boringssl 需要 libunwind-generic 这个module的支持 yum install libunwind-devel libunwind # 注意这里的git仓库很大,大概在250MB左右,请确保编译安装服务器的网络良好 git clone https://github.com/google/boringssl.git cd boringssl/ # 建立一个专门用于编译的文件夹 mkdir build cd build cmake -GNinja .. ninja
注意在执行cmake这一步的时候正常情况下检测到的gcc文件和perl库版本应该是我们之前编译安装好的新版本,如果不对的话需要再次检查
# cmake -GNinja .. -- The C compiler identification is GNU 10.2.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/cc - skipped -- Detecting C compile features -- Detecting C compile features - done -- The CXX compiler identification is GNU 10.2.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /usr/bin/c++ - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Found Perl: /usr/bin/perl (found version "5.32.0") -- Checking for module 'libunwind-generic' -- Checking for module 'libunwind-generic' -- Found libunwind-generic, version 1.2 -- The ASM compiler identification is GNU -- Found assembler: /usr/bin/cc -- Configuring done -- Generating done -- Build files have been written to: /root/boringssl/build
2.7 编译nginx
剩下的nginx的编译安装步骤就和正常的nginx编译安装一致,这里不再赘述,模块可以根据自己的需求进行安装,开启HTTP/3模块需要使用--with-http_v3_module --with-cc-opt="-I../boringssl-master/include" --with-ld-opt="-L../boringssl-master/build/ssl -L../boringssl-master/build/crypto"
参数。
cd nginx-quic/ ./auto/configure \ --prefix=/usr/local/nginx \ --with-http_v3_module \ --with-cc-opt="-I../boringssl/include" \ --with-ld-opt="-L../boringssl/build/ssl -L../boringssl/build/crypto" \ --with-http_v3_module \ --with-http_quic_module \ --with-stream_quic_module \ --with-file-aio \ --with-http_ssl_module \ --with-http_v2_module \ --with-stream=dynamic \ --with-stream_ssl_module make make install
安装完成后我们检测nginx的参数:
#nginx -V nginx version: andblog.cn/1.21.4 built by gcc 10.2.0 (GCC) built with OpenSSL 1.1.1 (compatible; BoringSSL) (running with BoringSSL) TLS SNI support enabled
3、配置nginx-quic
-
由于HTTP/3需要使用udp协议端口,请注意开放对应的防火墙
-
http2监听的是443的tcp端口,而http3监听的是udp端口
-
nginx中添加了
$http3
和$quic
变量,可以添加到日志中,这样就可以看到是否使用了HTTP/3来进行访问了 -
如果有多个server_name,在不指定IP的情况下,只需要在任意一个配置了
listen 443 http3 quic reuseport;
那么其他所有server_name都会开启HTTP3,并且不需要再添加该配置否则会报错(不知道后续会不会把报错去掉),如果需要部分server_name开启HTTP/3,请指定监听IP。 -
http3增加了
http3_max_field_size
、http3_max_table_capacity
、http3_max_blocked_streams
、http3_max_concurrent_pushes
、http3_push
、http3_push_preload
这六个变量来控制http3的性能
http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; gzip on; gzip_min_length 1k; gzip_comp_level 6; gzip_types text/plain application/javascript application/x-javascript text/css application/xml; gzip_vary on; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; ssl_certificate /usr/local/nginx/conf/ssl/fullchain.pem; ssl_certificate_key /usr/local/nginx/conf/ssl/privkey.pem; include /usr/local/nginx/conf/mime.types; default_type application/octet-stream; ssl_stapling_verify on; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:1m; ssl_verify_depth 10; ssl_session_timeout 30m; ssl_protocols TLSv1.2 TLSv1.3; ssl_ecdh_curve X25519:P-256:P-384; ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256; # 添加HSTS配置 add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; # 添加header告知浏览器支持http3,注意这里不再需要像之前的草稿版本http3那样指定如h3-27 h3-28 h3-29等版本 add_header Alt-Svc 'h3=":443"; ma=86400'; # 开启 TLS 1.3 0-RTT ssl_early_data on; # 添加 Early-Data 头告知后端, 防止重放攻击 proxy_set_header Early-Data $ssl_early_data; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /usr/local/nginx/conf/conf.d/*.conf; } #cat api.andblog.cn.conf server { listen 443 ssl http2; server_name api.andblog.cn; client_max_body_size 100m; location / { proxy_pass http://127.0.0.1:8081; } error_page 403 404 https://andblog.cn; }
修改配置运行之后应该能看到udp的443端口被nginx进程监听
使用ss -tunl | grep 443来查看是否有端口监听
4、测试
目前的主流浏览器只有Firefox和Chrome支持了HTTP/3协议。并且两者支持程度并不高,Firefox是默认禁用,Chrome是默认开启部分,因此配置起来有点麻烦。
4.1 HTTP/3 CHECK
http3check.net
网站提供了网站的HTTP/3
支持检测
参考:https://tinychen.com/20200821-nginx-quic-compile-to-implement-http3/#3%E3%80%81%E9%85%8D%E7%BD%AEnginx-quic
评论前必须登录!
注册