Stay Hungry. Stay Foolish.

简单介绍

Nginx 是一个异步框架的 Web服务器,也可以用作反向代理,负载平衡器 和 HTTP缓存,由于其开源和高性能高并发的特点,被多种网站广泛使用,其中自然也少不了 Google。显然 Google 不会直接使用官方版的 Nginx 或是 Nginx-Plus,而是自己维护一个 Nginx 分支,据称有显著提升了性能,今天就拿 Google-Nginx 来测试了一下。

编译安装 Nginx-Google

安装 Bazel

操作环境:Debian 9.5。与一般使用 GCC / Clang 编译不同,Google 推荐使用 Bazel 来编译 Nginx,首先安装 Bazel

sudo apt -y install openjdk-8-jdk
echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
sudo apt update && sudo apt install bazel pkg-config zip g++ zlib1g-dev unzip python-dev cmake build-essential autoconf automake libjemalloc-dev libssl-dev git software-properties-common -y 

编译安装 Nginx

cd /usr/local/src
git clone https://nginx.googlesource.com/nginx
cd nginx
bazel build :nginx-google.deb

编译速度提升非常明显,而且编译过程也非常快速,编译完成后会生成一些 bazel 开头的文件夹指向编译目录 /root/.cache/bazel/ 下的中间文件和生成文件。一般我们会去执行 make install 来进行安装,这边也有一些不同。

进入**生成文件目录 bazel_bin **,可以看到有编译生成的 deb 文件 ngbinx-google.deb,直接安装即可:

sudo dpkg -i nginx-google.deb

你甚至可以拷贝该文件到其他机器上来安装。

一些特有的配置

上面说到 Google 对 Nginx 做了一些强化,配置显然也会有所不同,选择最有特点的两项介绍一下:

Brotli

gzip on;
gunzip on;
gzip_vary on;
gzip_static on;
gzip_comp_level 8;
gzip_buffers 32 8k;
gzip_min_length 256;
gzip_proxied any;
gzip_disable "msie6";
gzip_http_version 1.0;
gzip_types application/javascript application/atom+xml application/rss+xml application/json application/xhtml+xml font/woff font/woff2 image/gif image/jpeg image/png image/svg+xml image/webp image/x-icon image/x-ms-bmp text/css text/x-component text/xml text/plain;
        
brotli on;
brotli_static on;
brotli_min_length 20;
brotli_buffers 32 8k;
brotli_comp_level 6;
brotli_types application/javascript application/atom+xml application/rss+xml application/json application/xhtml+xml font/woff font/woff2 image/gif image/jpeg image/png image/svg+xml image/webp image/x-icon image/x-ms-bmp text/css text/x-component text/xml text/plain;

BoringSSL

BoringSSL 是 Google 从 OpenSSL 拉出来的一个独立发展的分支,目前跟 OpenSSL 相比已经有很多不同之处了。BoringSSL 支持了一种名为「等价加密算法组(Equal preference cipher groups)」的配置,会被自动选择不同的加密算法应用于最合适的场景(支持 AES-NI 优先使用 AES-GCM,否则优先使用 ChaCha20)

补充 Nginx-Google 的完整编译参数

nginx version: nginx/1.15.0
built by Bazel
built by gcc 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) 
built with OpenSSL 1.1.0 (compatible; BoringSSL) (running with BoringSSL)
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --user=nginx --group=nginx --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/cache/nginx/client_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --with-compat --with-threads --with-poll_module --with-select_module --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-openssl=//external:boringssl --with-pcre=//external:pcre --with-pcre-jit --with-zlib=//external:zlib --add-module=//ngx_brotli:http_brotli_filter --add-module=//ngx_brotli:http_brotli_static

自行实现 nginx-google 部分功能

不考虑 Google 自行实现的一些 patch 以外,nginx-google 最特别的就是他的 BoringSSL 了,Cloudflare 也使用了 BoringSSL 作为钦定的 SSL 模块,下面就来示范编译,并支持 TLSv1.3

具体编译部分请参考 Nginx 编译安装教程

安装编译必备软件

这边都是选择的都是包安装的方式,如果条件允许,尽量编译安装相应最新版本

apt install golang cmake clang build-essential -y

下载 BoringSSL 并预编译

git clone https://github.com/S8Cloud/sslpatch.git
git clone -b master https://github.com/google/boringssl.git && cd boringssl
patch -p1 <../sslpatch/BoringSSL-enable-TLS1.3.patch
patch -p1 <../sslpatch/BoringSSL-enable-AES_CBC.patch
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DOPENSSL_SMALL=1 .. && make -j $(nproc)
cd .. && mkdir -p .openssl/lib && cd .openssl && ln -s ../include .
cd .. && cp build/crypto/libcrypto.* build/ssl/libssl.* .openssl/lib && cd ..

上面的过程看起来还是非常繁琐的,实际上也是。

其他 Nginx 模块

Brotli 模块

  • 选择了 Google 员工维护的最新版 Brotli
git clone https://github.com/eustas/ngx_brotli
cd ngx_brotli && git submodule update --init && cd ../

zlib 库

  • 选择了 Cloudflare 魔改版的 zlib,显著提高了性能,仅仅适用于 Nginx 相关的应用,不适合替换系统的 zlib 库
git clone https://github.com/cloudflare/zlib
cd zlib && ./configure && cd ..

pcre 库

  • 当然是选择最新版啦
wget -c https://ftp.pcre.org/pub/pcre/pcre-8.42.zip && unzip pcre-8.42.zip && rm pcre-8.42.zip
cd pcre-8.42 && ./configure && cd .. && mv pcre-8.42 pcre

pagespeed 模块

wget -c https://github.com/apache/incubator-pagespeed-ngx/archive/v1.13.35.2-stable.zip && unzip v1.13.35.2-stable.zip && rm v1.13.35.2-stable.zip && cd incubator-pagespeed-ngx-1.13.35.2-stable
wget -c https://dl.google.com/dl/page-speed/psol/1.13.35.2-x64.tar.gz && tar -xzvf 1.13.35.2-x64.tar.gz && rm 1.13.35.2-x64.tar.gz && cd .. && mv incubator-pagespeed-ngx-1.13.35.2-stable pagespeed 

Headers-more 模块

git clone https://github.com/openresty/headers-more-nginx-module.git

其他模块

已知 Nginx-ct 模块存在不兼容情况,而 Lua 模块理论上是兼容的。

编译 Nginx

git clone https://github.com/nginx/nginx.git && cd nginx && cp auto/configure .
patch -p1 < ../sslpatch/Nginx-cloudflare-combined-modern.patch
# patch -p1 < ../sslpatch/BoringSSL-enable-OCSP.patch

编译参数调整如下:

./configure --build=nginx-dcc --with-cc-opt='-g -O3 -m64 -march=native -ffast-math -DTCP_FASTOPEN=23 -fPIE -fstack-protector-strong -flto -fuse-ld=gold --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wno-unused-parameter -fno-strict-aliasing -fPIC -D_FORTIFY_SOURCE=2 -gsplit-dwarf' --with-ld-opt='-lrt -ljemalloc -Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now -fPIC' \
--prefix=/usr/share/nginx --sbin-path=/usr/sbin/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 \
--user=www-data --group=www-data \
--with-compat --with-file-aio --with-threads --with-poll_module --with-select_module --with-http_ssl_module --with-http_v2_module --with-http_v2_hpack_enc \
--with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_sub_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_degradation_module --with-http_secure_link_module --with-http_slice_module --with-http_stub_status_module \
--with-stream --with-stream_ssl_module --with-stream_realip_module --with-stream_ssl_preread_module \
--with-libatomic --with-zlib=../zlib --with-pcre=../pcre --with-pcre-jit \
--with-openssl=../boringssl --add-module=../ngx_brotli --add-module=../pagespeed --add-module=../headers-more-nginx-module --add-module=../ModSecurity-nginx

参数跑完成功以后一定要改一下 BoringSSL 的时间戳再编译

touch ../boringssl/.openssl/include/openssl/ssl.h
make -j $(nproc) && make install

开启 TLSv1.3 draft-23 && draft-28

参数调整为如下即可:

ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
ssl_ciphers '[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]:[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:AES128-SHA';
ssl_ecdh_curve X25519:P-256:P-384;
ssl_prefer_server_ciphers on;

你会发现上面并没有 TLSv1.3ciphers,是的你没有看错!就是有这样的操作。

开启 OCSP Staping

以本站 comodo 证书为例

openssl ocsp -no_nonce \
    -respout /etc/ssl/ocsp.resp \
    -issuer  intermediate.pem \
    -cert    website.pem \
    -CAfile  ca-bundle.pem \
    -VAfile  ca-bundle.pem \
    -url     http://ocsp.comodoca.com/ 

website.pem 为站点证书,intermediate.pem中间证书+根证书,如果执行成功可以看到有 /etc/ssl/ocsp.resp 文件出现,即缓存的 ocsp_stapling_file

在 nginx 站点配置文件中添加如下内容即可:

ssl_stapling on;
ssl_stapling_file /etc/ssl/ocsp.resp;

注意 ocsp_stapling_file 7 天要更新一次

查看 SSLLABS 的测试吧:

注意目前需要在最新版 SSLLABS 上进行测试:

boringssl