Nginx+SSL+HTTP2配置简明指南 - 无垠
Axton
Always dream. Always explore.
无垠

Nginx+SSL+HTTP2配置简明指南

题外话

也算是一波三折,这个博客迁移到了阿里云ECS上。从虚机到“弹性Web托管”再到云服务器,估计这个博客也就安稳下来了,魔改还在继续,但服务器恐怕不会再迁移了。

在服务器上装了Nginx,配置了HTTPS和HTTP2,也是碰到了许多坑,这篇文章也算是一个简单的记录,目标是拿到SSL Lab的A+评分。

我有懒癌,小白速退。

在最最最前面

如果你有一台全新的云服务器,并且准备安装Nginx,不管有没有打算开HTTPS和HTTP2,尽可能安装Nginx 1.10.2+,也可以安装1.11.x的主线版本,并在编译Nginx的时候加入HTTP2模块,同时在编译 Nginx 时指定 OpenSSL 源码目录(1.0.2+),而不是使用系统自带的版本,这样可以开启ALPN,保证在新的浏览器上也能使用HTTP2。就算暂时不打算开启,谁知道你以后需不需要呢...

这样编译Nginx就能加入HTTP2模块和SSL模块:

./configure --with-http_v2_module --with-http_ssl_module

也可以加入其他模块,看你的需求了。

开始

其实非常简单,搞到你的证书,然后在Nginx配置server块里加上SSL就好了。

listen 443 ssl;
ssl_certificate key.csr;
ssl_certificate_key key.key;

但是现在访问HTTP还是未加密,除非手动输入HTTPS。于是加入跳转解决来问题:

if ($server_port !~ 443){
    rewrite ^/.*$ https://$host$uri;
}

同样放在server块里,不过从评论了解到 Nginx 官方更推荐另开一个 server 块来解决跳转。

这样就搞定了HTTPS的配置,先去SSL Lab里面溜溜。

https://acdn.flyhigher.top/wp-content/uploads/2017/04/snipaste20170404_084447.jpg

???居然只有B?忍不了,于是准备优化。

进一步优化

首先我们要开启HSTS。

科普一下,一般情况下我们输入域名访问网站,若是不指定协议,浏览器会默认使用HTTP协议,然后才因为我们上一节的设置转到HTTPS协议。这就给了中间人攻击可乘之机。

使用HSTS(HTTP严格传输安全),在第一次访问后浏览器就会知道你的站点长时间开启HTTPS。这样,在你指定的过期时间之前浏览器就会在内部强制307到HTTPS,这样就避免了HTTP跳转的问题。

开启HSTS:

add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" always;

max-age参数规定了这一设定的过期时间, includeSubdomains参数表明所有子域名也需要开启HSTS,always参数表明Nginx在任何情况下都会输出这一头部。加入server块即可。

当然需要注意,开启HSTS之后,设置过期之前你站点的证书不能失效,不能试图在服务器端强制走HTTP,这都会导致站点无法访问。

而且开启HSTS后,第一次访问站点仍然会走HTTP转HTTPS,毕竟浏览器不知道嘛。HSTS Preload可以解决这个问题。

谷歌维护了一份HSTS Preload List,且这一列表各大浏览器都承认。在这一列表里的域名浏览器会知道直接使用HTTPS,这样就完全避免了走HTTP。

任何人都可以申请将自己的域名加入这一列表。但如果要想把自己的域名 加进 这个列表,需要满足以下条件:

  • 有效的证书
  • 将所有 HTTP 流量重定向到 HTTPS
  • 确保所有子域名都启用了 HTTPS
  • 输出 HSTS 响应头,且
    • max-age 至少需要 18 周(10886400 秒)
    • 必须指定 includeSubdomains 参数
    • 必须指定 preload 参数

而且貌似满足了这些条件申请也不一定通过。Anyway,申请地址(科学上网):https://hstspreload.appspot.com

注意一旦加入这一列表,撤销据说异常困难,只有在你保证可以长时间提供HTTPS服务的情况下才应该申请加入。

至少我是不打算申请了...比较咱小站没必要,何况我的子域名解析到了好几台服务器上,恐怕一时半会儿也不能保证全部HTTPS,慢慢来吧。

下一步是使用更安全的加密算法。

很简单,把这些配置加入server块:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;

这会让服务器使用更强的加密算法(如果客户端支持)。另外建议,直接让服务器关闭对IE 6的连接好了。IE 6只支持部分弱加密算法,应该被淘汰了。

然后开启SSL缓存。

开启SSL缓存可以让浏览器在一定时间里缓存SSL加密。这样,在这段时间里发起的SSL连接就可以减少相当的加密时间,这对减轻服务器和客户端计算压力都有不小的好处。

同样放进server块:

ssl_session_timeout 1d;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_buffer_size 1400;

这样就好了。做到目前这一步,SSL就已经配置好了。最后一步,加入HTTP2。

也是非常简单。更改listen:

listen 443 ssl http2;

这样就开启了HTTP2。注意,Ngnix 1.10.1及以下版本还是不要开启了,会有POST Bug,详见https://imququ.com/post/nginx-http2-post-bug.html

最后重启Ngnix,到SSL Lab里面清除缓存再跑一次:

https://acdn.flyhigher.top/wp-content/uploads/2017/04/snipaste20170404_085128.jpg

完美!

当然到了这一步也还是有优化的地方的,比如说加入HTTP Public Key Pinning(HPKP)。然而有些设置实在太麻烦,何况没必要,还会牺牲兼容性,得不偿失...

赞赏
本文链接:https://flyhigher.top/works/net/367.html
本文采用 CC BY-NC-SA 3.0 Unported 协议进行许可

发表回复

textsms
account_circle
email

无垠

Nginx+SSL+HTTP2配置简明指南
题外话 也算是一波三折,这个博客迁移到了阿里云ECS上。从虚机到“弹性Web托管”再到云服务器,估计这个博客也就安稳下来了,魔改还在继续,但服务器恐怕不会再迁移了。 在服务器上装了…
扫描二维码继续阅读
2017-04-04