QUIC上手初体验

安装支持HTTP3的nginx,通过cloudflare云服务开源的quiche实现,其中主要涉及内容包括

  • nginx源码
  • 由cloudflare开源于github的quiche项目(quiche从nginx-1.16.x版本开始支持)
  • 由google开源于github的boringssl项目(在quiche项目中引用了该项目)
  • Rust语言环境(cloudflare/quiche项目build需要)
  • Golang语言环境(google/boringssl项目make需要)
  • 支持https的curl最新版本
  • SSL证书生成

首先确定工作路径为~/tools.

安装nginx可能涉及模块的各项依赖,以及用于生成证书的openssl工具:

1
sudo apt install make cmake libssl-dev libpcre3 libpcre3-dev zlib1g-dev openssl autoconf libtool golang-go

注:整个安装过程须全程连网。

一、安装Rust语言环境

通过官方安装方式,执行以下命令之后,将下载对应语言环境安装包(大约170MB),期间有部分操作需人为干预,按提示输入对应内容回车即可。参考官方文档:

1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

一般情况下,Rust安装在用户目录的.cargo/bin路径下,需将该路径加入到PATH变量中,可在/etc/profile文件最后追加如下内容:

1
export PATH=$PATH:/home/zero/.cargo/bin

除此之外,还需指定默认工具链:

1
sudo rustup default stable

随后可通过如下命令验证Rust语言环境是否安装成功:

1
2
3
4
5
zero@zero:~$ rustc --version
rustc 1.44.1 (c7087fe00 2020-06-17)
zero@zero:~$ cargo --version
cargo 1.44.1 (88ba85757 2020-06-11)
zero@zero:~$

注: 国内访问create.io站点较慢,在后续使用中将从该站点下载必要文件,故采用配置使用镜像站,在~/.cargo目录下创建config文件,输入并保存以下内容:

1
2
3
4
5
[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = 'ustc'
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"

二、下载quiche项目源码

通过git直接将cloudflare/quiche项目源码克隆到本地,直接使用master分支:

1
git clone --recursive https://github.com/cloudflare/quiche

注: --recursive 参数是用于处理git依赖的子项目,在quiche项目clone完成并检出master分支之后可在项目目录下看到.gitmodule文件,其中即是关联子模块的git配置信息,即在clone完成主项目之后立即执行子项目clone至默认配置的目录

注: 网络环境较差情况下,由于google/boringssl项目文件内容较多(大于100MB),直接使用--recursive可能失败,如果在 quiche/deps/boringssl目录下无.git等相关文件(即前面的--revursice执行失败了),则可单独到quiche/deps目录下,首先删除boringssl空文件夹,单独clonegoogle/boringssl项目到deps目录下,并在quiche项目下使用git的子模块修复命令修复:

1
2
3
4
5
6
7
8
9
cdo ~/tools/quiche/deps

rmdir boringssl

git clone https://github.com/google/boringssl.git

cd ../

git submodule update --init

如果修复成功会有类似如下提示(后面的commitId可能不同,可以忽略):

1
2
zero@zero:~/tools/quiche$ git submodule update --init 
Submodule path 'deps/boringssl': checked out '88024df12147e56b6abd66b743ff441a0aaa09a8'

三、准备CA证书文件

确定存放CA证书文件的路径为~/tools/openssl.

1
cd ~/tools/openssl

1、使用openssl使用des3算法生成2048位的rsa私钥,此处需输入预置解析密码(需记下以备后用,譬如 ‘123456’)

1
openssl genrsa -des3 -out server.key 2048

注:查看刚生成的私钥(需键入解析密码):

1
openssl rsa -text -in server.key

2、根据刚生成的私钥创建证书签名请求CSR文件,此处需键入包含公司、国家编码、地区编码等信息:

1
openssl req -new -key server.key -out server.csr

注:查看生成CSR文件详情:

1
openssl req -text -in server.csr -noout

3、删除密钥中的密码,避免在使用该证书的应用加载时需要输入解析密码的操作:

1
openssl rsa -in server.key -out server.key

4、生成时间为10年(尽量长一点时间)的CA证书:

1
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

以上一顿操作之后便能在~/tools/openssl目录下看到如下文件:

1
2
3
4
5
6
7
zero@zero:~$ ls -a -l -h tools/openssl/
total 20K
drwxrwxr-x 2 zero zero 4.0K Jul 4 03:39 .
drwxrwxr-x 8 zero zero 4.0K Jul 4 03:36 ..
-rw-rw-r-- 1 zero zero 1.3K Jul 4 03:39 server.crt
-rw-rw-r-- 1 zero zero 1.1K Jul 4 03:39 server.csr
-rw------- 1 zero zero 1.7K Jul 4 03:42 server.key

四、编译支持HTTP3的nginx

转至nginx工作目录下载并解压源码,下载大于或等于1.16.x的nginx版本皆适用,此处使用当前最新稳定版本1.18.0:

1
2
3
4
5
cd ~/tools

curl -O https://nginx.org/download/nginx-1.18.0.tar.gz

tar -zxf nginx-1.18.0.tar.gz

参考转到nginx源码目录,将cloudflare/quiche项目有关nginx的源码附加到nginx源码中:

1
patch -p01 < ../quiche/extras/nginx/nginx-1.16.patch

配置编译的nginx支持HTTP/3:

1
2
3
4
5
6
7
8
./configure                                    \
--prefix=/usr/local/etc/nginx-1.18.0 \
--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/deps/boringssl \
--with-quiche=../quiche

编译:

1
sudo make install

将安装nginx的路径加入到PATH变量,并启动nginx:

1
export PATH=$PATH:/usr/local/etc/nginx-1.18.0/sbin

或编辑/etc/sudoers文件,在’secure_path’后面增加nginx安装路径:

1
Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/usr/local/etc/nginx-1.18.0/sbin"

查看编译的nginx版本信息:

1
2
3
4
5
6
7
zero@zero:~/tools/nginx-1.18.0$ nginx -V 
nginx version: nginx/1.18.0 (quiche-c25a595)
built by gcc 9.3.0 (Ubuntu 9.3.0-10ubuntu2)
built with OpenSSL 1.1.0 (compatible; BoringSSL) (running with BoringSSL)
TLS SNI support enabled
configure arguments: --prefix=/usr/local/etc/nginx-1.18.0 --build=quiche-c25a595 --with-http_ssl_module --with-http_v2_module --with-http_v3_module --with-openssl=../quiche/deps/boringssl --with-quiche=../quiche
zero@zero:~/tools/nginx-1.18.0$

编辑配置文件/usr/local/etc/nginx-1.18.0/conf/nginx.conf,配置监听端口并启用QUIC监听443端口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
http {
server {
# Enable QUIC and HTTP/3.
listen 443 quic reuseport;

# Enable HTTP/2 (optional).
listen 443 ssl http2;

ssl_certificate /home/zero/tools/openssl/server.crt;
ssl_certificate_key /home/zero/tools/openssl/server.key;

# Enable all TLS versions (TLSv1.3 is required for QUIC).
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

# Request buffering in not currently supported for HTTP/3.
proxy_request_buffering off;

# Add Alt-Svc header to negotiate HTTP/3.
add_header alt-svc 'h3-29=":443"; ma=86400';
}
}

启动nginx,并查看端口监听情况:

1
2
3
4
5
6
7
8
9
zero@zero:/usr/local/etc/nginx-1.18.0$ sudo nginx -c /usr/local/etc/nginx-1.18.0/conf/nginx.conf
zero@zero:/usr/local/etc/nginx-1.18.0$ ps -ef |grep nginx
root 88516 1 0 07:24 ? 00:00:00 nginx: master process nginx -c /usr/local/etc/nginx-1.18.0/conf/nginx.conf
nobody 88517 88516 0 07:24 ? 00:00:00 nginx: worker process
zero 88519 4508 0 07:24 pts/1 00:00:00 grep --color=auto nginx
zero@zero:/usr/local/etc/nginx-1.18.0$
zero@zero:/usr/local/etc/nginx-1.18.0$ ss -lunt |egrep ':80|:443'
udp UNCONN 0 0 0.0.0.0:443 0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:*

五、编译支持HTTP/3的curl工具

首先到quiche目录下编译quiche和BoringSSL:

1
2
3
4
5
6
7
cd ~/tools/quiche

sudo cargo build --release --features pkg-config-meta,qlog

mkdir deps/boringssl/lib

sudo ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) deps/boringssl/lib/

转至~/tools/目录下通过git将curl/curl项目源码下载到~/tools工作目录下,直接使用master分支即可:

1
2
3
cd ~/tools

git clone https://github.com/curl/curl.git

转到curl目录下编译curl:

1
2
3
4
5
6
7
cd curl

./buildconf

./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-ssl=$PWD/../quiche/deps/boringssl --with-quiche=$PWD/../quiche/target/release --enable-alt-svc --prefix=/usr/local/etc/curl

sudo make

先卸载原有的curl,再将安装curl的路径加入到PATH变量:

1
2
3
sudo apt remove curl

export PATH=$PATH:/usr/local/etc/curl/bin

编译成功后,curl工具在src目录下,通过curl请求HTTP/3示例:

1
2
3
4
5
6
7
8
9
10
11
zero@zero:~/tools/curl$ curl --http3 https://localhost -k -I 
HTTP/3 200
server: nginx/1.18.0
date: Sat, 04 Jul 2020 05:28:15 GMT
content-type: text/html
content-length: 612
last-modified: Tue, 21 Apr 2020 14:09:01 GMT
etag: "5e9efe7d-264"
alt-svc: h3-29=":443"; ma=86400
accept-ranges: bytes
zero@zero:~/tools/curl$

参考:

nginx集成quiche
编译curl
boringssl