给 Nginx 添加 TLS1.3 支持

05/31/18 UPDATE: 感谢 kn007 推荐的 OpenSSL Patch (hakasenyang) 可以同时使用 Draft 23, Draft 26 和 Draft 28.

05/19/18 UPDATE: Cloudflare 已默认给新老用户开启 TLS 1.3 协议, 详情见 https://blog.cloudflare.com/you-get-tls-1-3-you-get-tls-1-3-everyone-gets-tls-1-3

03/14/18 UPDATE: 从 Chrome 65 开始 Chrome 会默认开启并使用 TLSv1.3 Draft 23, Cloudflare 目前也使用的 Draft 23.

前言

TLS1.3 草案出来有很长一段时间了, Chrome, Firefox 以及 Cloudflare 的 CDN 也早加入了实验性支持, 所以就很想试试, 结果找了半天并没有找到解决方案, 很气. 直到后来无意看到 OpenSSL 的代码库 多了个 tls1.3-draft-18 的分支 就贼高兴, 折腾了半天之后终于成功给 Nginx 开启了 TLS1.3.

注: Nginx 1.13.0 开始 正式支持 ssl_protocols 的 TLSv1.3 的选项. 在此之前 TLSv1.2 选项会自动使用 TLSv1.3.

OpenSSL 目前有 draft-18 分支, pre2 版本的 draft-23 以及 pre7+ 的 draft-28 通过 tls1.h (include/openssl/tls1.h 第35行) 可以查看目前的 Draft…

从 Chrome 65 开始会默认开启并使用 TLSv1.3 Draft 23, 从 Chrome 68 开始支持 Draft 28 (Firefox Nightly 应该也支持).

另 吐槽一点 不知道什么原因 编译出来的 Nginx 不管怎么搞, SSL Labs 测试 TLSv1.1 都是 关的 望指点…

编译安装

依赖

#CentOS
sudo yum groupinstall -y "Development Tools"
sudo yum install -y git wget zlib zlib-devel pcre-devel google-perftools google-perftools-devel lua-devel GeoIP-devel

#Debian/Ubuntu
sudo apt update
sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g-dev liblua5.1-dev libluajit-5.1-dev libgeoip-dev google-perftools libgoogle-perftools-dev

#Clang(CentOS)(Optional) From http://i.hanicka.net
echo -e "[llvm]\nname=LLVM for CentOS-\$releasever\nbaseurl=https://llvm.cpp.fail/CentOS/\$releasever/llvm/\$basearch/\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=https://llvm.cpp.fail/gpg.key" | sudo tee /etc/yum.repos.d/llvm.repo
sudo yum install clang clang-devel libc++ libc++-devel lld lldb lldb-devel llvm llvm-devel binutils devtoolset-7

#Clang(Debian)(Optional) Ubuntu see here http://apt.llvm.org
echo -e "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch main\ndeb-src http://apt.llvm.org/stretch/ llvm-toolchain-stretch main" | sudo tee /etc/apt/sources.list.d/llvm.list
sudo apt install clang-7 lldb-7 lld-7 llvm

mkdir ~/Swift && cd ~/Swift

#下载 Nginx 1.15.1
wget https://nginx.org/download/nginx-1.15.1.tar.gz
tar zxf nginx-1.15.1.tar.gz

#下载 OpenSSL 1.1.1-pre8
wget https://www.openssl.org/source/openssl-1.1.1-pre8.tar.gz
tar zxf openssl-1.1.1-pre8.tar.gz

#打 TLS1.3 Draft 23,26,28 补丁
#根据 OpenSSL 版本决定, 具体见 https://github.com/hakasenyang/openssl-patch
pushd openssl-1.1.1-pre8
wget https://raw.githubusercontent.com/hakasenyang/openssl-patch/master/openssl-equal-pre8.patch
patch -p1 < openssl-equal-pre8.patch
popd

#打 SPDY, HTTP2 HPACK, Dynamic TLS Record, PRIORITIZE_CHACHA, Fix Http2 Push Error 补丁 (推荐)
#此补丁不一定适用于最新的 Nginx 已测试通过的版本请查看 https://github.com/kn007/patch
pushd nginx-1.15.1
wget https://raw.githubusercontent.com/kn007/patch/45f1417c450fc82cd470cb73a32e23085c4ba3d5/nginx.patch
wget https://raw.githubusercontent.com/kn007/patch/c59592bc1269ba666b3bb471243c5212b50fd608/nginx_auto_using_PRIORITIZE_CHACHA.patch
wget https://raw.githubusercontent.com/kn007/patch/b70155131a74deafe9c642194b4394edda20ccec/fix_nginx_hpack_push_error.patch
patch -p1 < nginx.patch
patch -p1 < nginx_auto_using_PRIORITIZE_CHACHA.patch
patch -p1 < fix_nginx_hpack_push_error.patch
popd

#拉取 ngx_brotli (Optional)
git clone https://github.com/eustas/ngx_brotli.git
pushd ngx_brotli
git submodule update --init
popd

#拉取 lua-nginx-module (Optional)
git clone https://github.com/openresty/lua-nginx-module.git

#拉取 nginx-sorted-querystring-module (Optional)
git clone https://github.com/wandenberg/nginx-sorted-querystring-module.git

#拉取 ngx_http_substitutions_filter (Optional)
git clone https://github.com/yaoweibin/ngx_http_substitutions_filter_module.git

编译

我目前使用 clang-7 编译 Nginx, 如果你用 GCC 请删除 –with-cc –with-cpp 及 ./configure 之前的内容

使用 --with-openssl=../openssl-1.1.1-pre8 来指定 OpenSSL 路径

目前 OpenSSL 开启 TLS1.3 需要 加入 --with-openssl-opt=enable-tls1_3

TLSv1.3 is enabled by default in the latest development versions (there is no need to explicitly enable it). To disable it at compile time you must use the “no-tls1_3” option to “config” or “Configure”.
https://www.openssl.org/blog/blog/2018/02/08/tlsv1.3/

HTTP2 HPACK 需要加入 --with-http_v2_hpack_enc

SPDY 需要加入 --with-http_spdy_module

其他参数自己按需控制

cd nginx-1.15.1

CFLAGS="-flto" CXXFLAGS="-flto" LDFLAGS="-fuse-ld=lld -flto" ./configure \
--with-cc='clang -flto' \
--with-cpp='clang++ -flto' \
--sbin-path=/usr/sbin/nginx \
--prefix=/usr/share/nginx \
--conf-path=/etc/nginx/nginx.conf \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
--lock-path=/var/lock/nginx.lock \
--pid-path=/run/nginx.pid \
--modules-path=/usr/lib/nginx/modules \
--http-client-body-temp-path=/var/lib/nginx/body \
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
--http-proxy-temp-path=/var/lib/nginx/proxy \
--http-scgi-temp-path=/var/lib/nginx/scgi \
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi \
--with-threads \
--with-file-aio \
--with-pcre-jit \
--with-http_v2_module \
--with-http_ssl_module \
--with-http_sub_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_gzip_static_module \
--with-http_degradation_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_random_index_module \
--with-http_auth_request_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-stream_realip_module \
--with-http_slice_module \
--with-http_geoip_module \
--add-module=../ngx_brotli \
--add-module=../lua-nginx-module \
--add-module=../nginx-sorted-querystring-module \
--add-module=../ngx_http_substitutions_filter_module \
--with-google_perftools_module \
--with-openssl=../openssl-1.1.1-pre8 \
--with-http_v2_hpack_enc \
--with-http_spdy_module

过程中 可能会报错 not found 根据提示把依赖装完就可以编译了

make -j8 && sudo make install

测试

nginx -t

如果都是 OK 那么 一切没问题.

配置 Nginx

Brotli (Optional)

sudo vim /etc/nginx/nginx.conf
在 http{} 中加入
brotli on;
brotli_static on;
brotli_comp_level 6;
brotli_buffers 32 8k;

TLS1.3

ssl_protocols 中加入 TLSv1.3 (仅 Nginx 1.13.0 及以上, 低版本用 TLSv1.2 就行)

ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;

修改 ssl_ciphers ( openssl-patch 参考 )

ssl_ciphers [EECDH+ECDSA+AESGCM+AES128|EECDH+ECDSA+CHACHA20]:EECDH+ECDSA+AESGCM+AES256:EECDH+ECDSA+AES128+SHA:EECDH+ECDSA+AES256+SHA:[EECDH+aRSA+AESGCM+AES128|EECDH+aRSA+CHACHA20]:EECDH+aRSA+AESGCM+AES256:EECDH+aRSA+AES128+SHA:EECDH+aRSA+AES256+SHA;

最后 使用nginx -t测试一下 确认无问题

开启浏览器支持

Chrome 65-67 默认支持 TLS1.3 Draft 23, Chrome 68+ 支持 Draft 28

Firefox Nightly 支持 Draft 28, 正式版不清楚.

测试效果

Chrome 67 (Draft 23):

Firefox Nightly (Draft 28):

SSL Test 结果

测试网址: https://api.love4taylor.me/ssltest/