首页 >> 网页技术 > 网站优化 >> 详细内容
网站优化 >> 正文
在 nginx 中配置 HTTP/2 支持
日期:2017/9/19 

HTTP/2 协议于 2015 年 5 月 14 日正式版发布。随着 nginx 等流行 webserver 以及各大浏览器对 HTTP/2 的支持,越来越多的网站开始部署 HTTP/2 了。

HTTP/2 协议

HTTP/2 源自 SPDY/2。SPDY 系列协议由谷歌开发,于 2009 年公开。它的设计目标是降低 50% 的页面加载时间。

HTTP/2 协议由以下两个 RFC 组成:

RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)
RFC 7541 - HPACK: Header Compression for HTTP/2

 HTTP/2 官网 可以找到更多有关 HTTP/2 协议的资料。

HTTP/2 特点

HTTP/2 在底层传输上带来了大量的改动与优化,简单来讲,就是可以使得页面更快更持久。

二进制格式传输数据

HTTP/2 采用二进制格式传输数据。二进制格式在协议的解析和优化扩展上带来更多的优势和可能。

消息头压缩传输

HTTP/2 对消息头采用 HPACK 进行压缩传输,能够节省消息头占用的网络的流量。而 HTTP/1.x 每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。头压缩能够很好的解决该问题。

多路复用

利用多路复用可以实现延迟削减。

每个 Frame Header 都有一个 Stream ID 就是被用于实现该特性。每次请求/响应使用不同的 Stream ID。就像同一个 TCP 链接上的数据包通过 IP:PORT来区分出数据包去往哪里一样。通过 Stream ID 标识,所有的请求和响应都可以欢快的同时跑在一条 TCP 链接上了。

当流并发时,就会涉及到流的优先级和依赖。优先级高的流会被优先发送。图片请求的优先级要低于 CSS 和 SCRIPT,这个设计可以确保重要的东西可以被优先加载完。

直白的说就是所有的请求都是通过一个 TCP 连接并发完成。HTTP/1.x 虽然通过 pipeline 也能并发请求,但是多个请求之间的响应会被阻塞的,所以 pipeline 至今也没有被普及应用,而 HTTP/2 做到了真正的并发请求,同时,流还支持优先级和流量控制。

服务器推 (Server Push)

当服务端需要主动推送某个资源时,便会发送一个 Frame Type 为 PUSH_PROMISE 的 Frame,里面带了 PUSH 需要新建的 Stream ID。意思是告诉客户端:接下来我要用这个 ID 向你发送东西,客户端准备好接着。客户端解析 Frame 时,发现它是一个 PUSH_PROMISE 类型,便会准备接收服务端要推送的流。

这使得服务端能够更快的把资源推送给客户端。例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 HTML 再发送这些请求。当客户端需要的时候,它已经在客户端了。

nginx 启用 HTTP/2 支持

nginx 在 1.9.5 以后开始支持 HTTP/2,并且移除了 SPDY 模块。只需将http2 添加到所有 listen 指令当中即可。示例:

01 server {
02     server_name lzw.me;
03     root /site/xxx;
04     listen 443 ssl http2 fastopen=3 default_server;
05  
06     # 证书
07     ssl_certificate     /etc/ssl_cert/lzw.me.crt;
08     ssl_certificate_key /etc/ssl_cert/lzw.me.key;
09  
10     # 配置赫尔曼密钥
11     # openssl dhparam -out /etc/ssl/dhparam.pem 2048 //openssl 生成 2048 位的密钥
12     ssl_dhparam /etc/ssl_cert/dhparam.pem;
13  
14     # 禁止已经不安全的加密算法
15     ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4';
16  
17     # 缓解 BEAST 攻击
18     ssl_prefer_server_ciphers on;
19  
20     # OCSP 缝合
21     ssl_stapling on;
22     ssl_stapling_verify on;
23     ssl_trusted_certificate /etc/nginx/cert/trustchain.crt;
24     resolver 114.114.114 8.8.8.8 valid=300s;
25  
26     # 禁止不安全的 SSL 协议,使用安全协议
27     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
28  
29     # 缓存连接凭据
30     ssl_session_cache shared:SSL:20m;
31     ssl_session_timeout 60m;
32  
33     # 启用 HSTS,要求浏览器总是通过 https 访问
34     add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains; preload';
35     # 禁止被外部网站 iframe
36     add_header X-Frame-Options SAMEORIGIN;
37     # 严格的 MIME 类型响应,禁止 MIME-sniffing 猜测资源类型
38     add_header X-Content-Type-Options nosniff;
39  
40     # Public Key Pinning 对抗中间人攻击
41     # 生成方法参考:https://lzw.me/a/public-key-pins-hpkp.html
42     add_header Public-Key-Pins 'pin-sha256="oYQpJ7NWxATnj4TXRpTIKMECkarA0lPcAblBBaV23Io="; pin-sha256="JGBhwHhyQ8RjdAiTim2KGnNegkNyBfISSuCL2YiSbTM="; max-age=2592000; includeSubDomains';
43  
44 }
45  
46 # 80 端口跳转到 https
47 server {
48     listen 80;
49     add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
50     return 301 https://lzw.me$request_uri;
51 }

支持 ALPN

chrome 51 之后,要求对 HTTP/2 只支持 ALPN,否则还是会使用 HTTP/1.1。openssl 在 1.0.2 之后的版本才支持 ALPN。如果你的 nginx 是使用动态链接方式支持 openssl,需要更新系统的 openssl 版本;如果 nginx 是使用静态编译方式,则需要重新编译。验证是否支持 ALPN:

openssl s_client -alpn h2 -servername lzw.me -connect lzw.me:443 < /dev/null | grep 'ALPN'

看到输出 ALPN protocol: h2 则说明是支持的。

如不支持,请参考下面的编译 nginx 方法。

编译 nginx 支持 ALPN

安装依赖库和编译要用到的工具(选择没有的进行安装):

sudo yum install build-essential libpcre3 libpcre3-dev zlib1g-dev unzip git

下载 openssl

unzip openssl.zip
mv openssl-OpenSSL_1_0_2h/ openssl

cd openssl
patch -p1 < ../sslconfig/patches/openssl__chacha20_poly1305_draft_and_rfc_ossl102g.patch 

cd ../

下载 nginx-ct,以启用 Certificate Transparency

wget -O nginx-ct.zip -c https://github.com/grahamedgecombe/nginx-ct/archive/v1.2.0.zip
unzip nginx-ct.zip
mv nginx-ct-1.2.0 nginx-ct

下载 nginx 并解压,执行编译安装

wget -c https://nginx.org/download/nginx-1.11.3.tar.gz
tar zxf nginx-1.11.3.tar.gz

cd nginx-1.11.3/

./configure --add-module=../nginx-ct-1.2.0 --with-openssl=../openssl --with-http_stub_status_module --with-http_v2_module --with-http_ssl_module --with-ipv6 --with-http_sub_module --with-http_gzip_static_module 
# 应根据实际情况添加 user 和 group 参数
# --prefix=/usr/local/nginx --user=www --group=www

make
sudo make install

验证网站对 HTTP/2 的支持