在Nginx中支持HTTP3.0/QUIC

在Nginx中支持HTTP3.0/QUIC

HTTP3.0,也称做HTTP over QUIC。核心是QUIC(读音quick)协议,由Google在2015年提出的SPDY v3演化而来的新协议,传统的HTTP协议是基于传输层TCP的协议,而QUIC是基于传输层UDP上的协议,能够定义成:HTTP3.0基于UDP的安全可靠的HTTP2.0协议,主要有如下特性:linux

图片来自Nginx官博
  • 基于UDP减小了TCP三次握手及TLS握手时间
  • 解决多路复用丢包时的线头阻塞问题
  • 优化重传策略
  • 流量控制
  • 链接迁移

本文主要讲解一下如何在Nginx中开启HTTP3.0的支持。nginx

方案选择

对于HTTP3.0,因为整个协议仍是处于草案阶段,目前来讲没有一个完整的标准,因此各大浏览器厂商还只是在开发者版本中才会支持,例如Chrome的金丝雀版本Chrome Canary[1],而且各个服务器厂商也是在持续跟进中,对于Nginx来讲,支持HTTP3.0目前有两种方案能够选择:c++

  • 基于Cloudflare的分支版本Nginx:对于HTTP3.0/QUIC,Cloudflare始终走在了前列,借助于自家维护的开源项目 quic [2],从Nginx中拉出了一个分支来开发,并编译出了对HTTP3.0支持的Nginx服务器。
  • Nginx官方Nginx-quic项目:今年6月10日,Nginx 官博 [3]发布公告称已经在研发支持HTTP3.0/QUIC协议的工做,目前项目维护在 nginx-quic [4],该项目和基于Cloudflare基于Nginx的分支并没有关系,算是相对于正统的方案。

基于此,本文将会以部署nginx-quic的方式来让Nginx支持HTTP3.0/QUIC。git

改造过程

咱们最终的目的是获得nginx-quic版本的nginx可执行文件,须要通过一系列的安装和编译,期间可能会遇到不少问题,若是各位读者不想实际操做,能够直接用我编译好的版本nginx-quic.linux-x86_64.zip 传送门[5]github

准备工做:

以centos7为例,下载nginx-quic源码传送门[6],下载完成以后,须要进行编译安装,因为nginx-quic依赖boringSSL,因此还需下载boringSSL源码传送门[7],而后一样须要编译安装boringSSL,执行这些操做以前,须要在linux上安装一些前置模块,经过yum来安装,执行如下命令:golang

sudo yum install build-essential mercurial psmisc lsb-release cmake golang libunwind-dev git libpcre3-dev zlib1g-dev

什么是boringSSL:

对于Nginx来讲,在编译时须要配置对于的SSL库,不论是HTTP3.0仍是HTTP2.0,始终都要基于HTTPS,而加密算法这块主要有OpenSSL来提供,而BoringSSL是谷歌建立的OpenSSL分支,用于支持TLS1.3的UDP协议0-RTT数据传输的加密算法(能够理解成TLS1.3是标准协议,BoringSSL是实现工具),BoringSSL的一些特性会在合适的时机同步给OpenSSl。web

编译安装boringSSL:

cd boringssl-master/
mkdir build
cd build
cmake ../
make

执行以后,能够在build/crypto,和build/ssl下得到对应的文件,以下图: 算法

注意编译安装boringSSL须要使用cmake3以上的版本。chrome

编译安装nginx-quic:

cd nginx-quic/
./auto/configure --prefix=/root/nginx --with-http_ssl_module --with-http_v2_module --with-http_v3_module --with-cc-opt="-I../boringssl-master/include" --with-ld-opt="-L../boringssl-master/build/ssl -L../boringssl-master/build/crypto"
make 
make install

执行命令以后,会在/root/nginx目录下生成对应的nginx可执行文件,以下图:centos

其中,配置文件在conf/下,nginx命令在sbin/目录下。

修改配置文件,启动nginx:

vi /root/nginx/conf/nginx.conf

添加http3配置:

server {
    listen 443 ssl http2;              # TCP listener for HTTP/2
    listen 443 http3 reuseport;  # UDP listener for QUIC+HTTP/3

    ssl_protocols       TLSv1.3; # QUIC requires TLS 1.3
    ssl_certificate     ssl/www.example.com.crt;
    ssl_certificate_key ssl/www.example.com.key;

    add_header Alt-Svc 'quic=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"'# Advertise that QUIC is available
}

其中,要求使用TLSv1.3版本,而且当浏览器不支持http3时,能够选择http2。另外,add_header Alt-Svc添加这个返回头不可缺乏。

  • Alt-Svc 全称为“Alternative-Service”,直译为“备选服务”。该头部列举了当前站点备选的访问方式列表,让服务器能够告诉客户端 “看,我在这个主机的这个端口用这个协议提供相同的服务”。通常用于在提供 “QUIC” 等新兴协议支持的同时,实现向下兼容。参考 MDN [8]

验证HTTP3生效:

因为目前浏览器对HTTP3.0/QUIC的支持性有限,能够经过http3check.net/[9]来验证站点启用HTTP3是否成功,以个人站点为例:

坑点总结

整个过程看似很简单,可是真正配置过程当中遇到了很多坑,前先后后加上搜索问题花了一天半的时间才真正解决,把这些问题记录下来,分享给你们。

开启UDP的443端口:

因为quic协议使用的是UDP的443端口,这个端口对于centos7来讲是默认关闭的,能够采用下面命令开启:

firewall-cmd --zone=public --add-port=443/udp --permanent

若是项目托管在阿里云上,须要更新ECS的安全组策略来对外开启对应的协议和端口,以下图:

TLS版本向下兼容:

因为使用了TLS 1.3,因此会修改对应加密算法,可是对于一些浏览器而言还不支持这么高的版本,尤为是对于苹果的Safari,因此,在配置nginx配置文件时,要多配置几个版本向下兼容,代码以下:

ssl_protocols       TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

-Werror错误问题:

在编译nginx-quic时,有时会遇到以下错误:

cc -c -pipe  -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I../boringssl-master/include -I src/core -I src/event -I src/event/modules -I src/os/unix -I objs \
 -o objs/src/os/unix/ngx_linux_sendfile_chain.o \
 src/os/unix/ngx_linux_sendfile_chain.c
cc -c -pipe  -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I../boringssl-master/include -I src/core -I src/event -I src/event/modules -I src/os/unix -I objs \
 -o objs/src/event/ngx_event_openssl.o \
 src/event/ngx_event_openssl.c
cc -c -pipe  -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I../boringssl-master/include -I src/core -I src/event -I src/event/modules -I src/os/unix -I objs \
 -o objs/src/event/ngx_event_openssl_stapling.o \
 src/event/ngx_event_openssl_stapling.c
cc -c -pipe  -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I../boringssl-master/include -I src/core -I src/event -I src/event/modules -I src/os/unix -I objs \
 -o objs/src/event/ngx_event_quic.o \
 src/event/ngx_event_quic.c
cc -c -pipe  -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I../boringssl-master/include -I src/core -I src/event -I src/event/modules -I src/os/unix -I objs \
 -o objs/src/event/ngx_event_quic_transport.o \
 src/event/ngx_event_quic_transport.c
src/event/ngx_event_quic_transport.c: In function ‘ngx_quic_create_stream’:
src/event/ngx_event_quic_transport.c:54:9: error: comparison is always true due to limited range of data type [-Werror=type-limits]
      : ((uint32_t) value) <= 16383 ? 2                                        \
         ^
src/event/ngx_event_quic_transport.c:1299:15: note: in expansion of macro ‘ngx_quic_varint_len’
         len = ngx_quic_varint_len(sf->type);
               ^
cc1: all warnings being treated as errors
make[1]: *** [objs/src/event/ngx_event_quic_transport.o] Error 1
make[1]: Leaving directory `/root/nginx-quic'
make: *** [build] Error 2
[root@iz2zehmi1ztqtx8tg6ca7gz nginx-quic]#

解决办法是:

cd nginx-quic\objs

vi Makefile

找到 CFLAGS = -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -I../boringssl-master/include将-Werror参数去掉。

reuseport只需配置一次:

假若有多个域名须要开启http3,则reuseport建议只在根域名上配置,若是一个配置文件中出现多个reuseport,会报错,配置以下:

    server {
        
        listen 443 ssl http2;              # TCP listener for HTTP/2
        listen 443 http3 reuseport;  # UDP listener for QUIC+HTTP/3

        server_name  www.nihaoshijie.com.cn default_server;

    }

    server {

        listen 443 ssl http2;        # TCP listener for HTTP/2
        listen 443 http3;  # UDP listener for QUIC+HTTP/3

        server_name  app.nihaoshijie.com.cn;

    }

编译安装时的性能问题:

若是编译安装时报相似下面的错误,多是主机的内容不足,须要关闭一些运行的程序来往下进行。

...
c++: internal compiler error: Killed (program cc1plus)

快开启你的HTTP3之旅吧!

参考资料

[1]

Chrome Canary: https://www.google.cn/chrome/canary/

[2]

cloudflare-quic: https://cloudflare-quic.com/

[3]

introducing-technology-preview-nginx-support-for-quic-http-3: https://www.nginx.com/blog/introducing-technology-preview-nginx-support-for-quic-http-3/

[4]

nginx-quic: https://hg.nginx.org/nginx-quic

[5]

nginx-quic.linux-x86_64.zip: https://www.nihaoshijie.com.cn/mypro/nginx-quic.linux-x86_64.zip

[6]

nginx-quic-source-code: https://hg.nginx.org/nginx-quic

[7]

boringssl-code: https://github.com/google/boringssl

[8]

MDN: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Alt-Svc

[9]

http3check: https://http3check.net/?host=www.nihaoshijie.com.cn

原链:https://juejin.cn/post/6850418105462571021


本文分享自微信公众号 - 云原生生态圈(CloudNativeEcoSystem)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。