本站的 HTTPS 配置篇

部署 HTTPS 通信前请按需准备好域名证书等杂项。本站的固定域名使用证书签发机构 Let’s Encrypt 自动签发的DV证书。首要步骤是通过认证域名所有权的方式从 Let’s Encrypt 获得自动签发本站DV证书的许可。认证域名和签发数字证书的过程完全依托自动化程序一次性完成域名认证和证书签发的全过程,签发的证书直接存储在服务器上的统一指定目录。Certbot 和 acme.sh 都是能够简单地自动签发和续签该证书的工具 ,支持多种版本的操作系统,对应的网站上也有详细的文档作为支持。

Nginx & Let’s Encrypt

Certbot 成功签发证书后会在下面这个目录储存证书文件,证书有效期为90天。

/etc/letsencrypt/live/

在90天的有效期内续签证书的办法也是通过程序自动执行完成的。下面的方法是采用 cron 来生成自动续签证书的计划任务。

# 编辑 crontab
sudo crontab -e
# 添加以下内容,内容为每天 3:15 AM 运行 certbot renew 并且重启 nginx
15 3 * * * /usr/bin/certbot renew --quiet --renew-hook "/bin/systemctl reload nginx"

给网站部署 HTTPS

Diffie-Hellman Group (TLS<=1.2):为了进一步提高网站安全性,你应该使用一个高强度的 Diffie-Hellman。下面生成长度为 4096 位的 DH group:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

生成一个高强的 DH group 需要花费一段时间,尤其是计算机运算能力弱、熵不足时生成该文件所耗费的时间会很长。

配置 Nginx TLS/SSL

我对本站服务器上的 Nginx 配置目录做了以下类型分类:

位于目录 /etc/nginx/ 下面的配置文件结构:
sites-available/ 可用的站点配置
sites-enabled/ 已启用的站点配置
snippets/ 储存片段化的配置文件
snippets/ssl-example.com.conf 示例站点的数字证书的存储位置
snippets/ssl-params.conf 可以被各子站点通用的 SSL 配置。
nginx.conf 最通用的全局配置。

创建一个站点的配置片段,指向 SSL 密钥和证书

作为示例,给 exmaple.com 创建单独的 SSL 配置并且储存于 /etc/nginx/snippets/ssl-example.com.conf

# 证书、私钥、证书链
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

在此文件中的 ssl_certificate 命令指向证书位置,ssl_certificate_key 命令指向证书密钥。

在nginx 1.11.0 以后已经增加了多证书的特性[参考:CHANGES],使Nginx根据兼容优先级规则加载不同类型的证书。比如,分别定义两组 “ssl_certificate” and “ssl_certificate_key”,使Nginx优先加载ECDSA证书或者RSA证书。

创建具有强加密设置的配置片段

SSL 配置文件参考一个网站 cipherli.st,本站位于 /etc/nginx/snippets/ssl-params.conf 配置内容如下:

# from https://cipherli.st
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
# and https://github.com/cloudflare/sslconfig/blob/master/conf
# and https://imququ.com/post/ecc-certificate.html

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
# 如果启用了 ECDSA + RSA 双证书,Cipher Suite 可以参考以下配置:
ssl_ciphers 'EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5';
# 如果优先使用 ECDSA+AES128-GCM 参考以下配置:
# ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES:RSA+3DES';
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# disable HSTS header for now
#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options SAMEORIGIN;
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;

调整本站的 Nginx 配置文件,开启 SSL

这里我已经复制了默认的 default 配置文件作为之后修改参数的参考内容。该修改针对 HTTPS 增加了 http2 的支持。同时为了从 HTTP 跳转到 HTTPS 页面,我让 Nginx 监听的 80 端口默认都会带上参数跳转到 HTTPS 的链接。而这里 example.com 和 www.example.com 两个域名之所以要分开写 return 是为了符合 HSTS Preload List 的申请要求。(该要求是从 HTTP 到 HTTPS 的跳转过程前后必须为同一个域名)

server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}
server {
    listen 80;
    listen [::]:80;
    server_name www.example.com;
    return 301 https://$server_name$request_uri;
}

server {

    # SSL configuration

    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    . . .

应用修改(Nginx)

检查配置文件的语法正确性使用 nginx -t,如果完全正确就能输出以下结果:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

完全没有语法的错误,重新启动 Nginx 从而加载新的配置文件:

systemctl restart nginx

现在,如果你通过上面的步骤部署的 HTTPS 能正常工作并且在 Qualys SSL Labs Report 获得了一个 A+ 的评级,说明部署大致已经成功了。如果遇到意料之外的问题而没能成功获得 A+ 评级的朋友请留言或者发邮件告诉我,谢谢!

4 thoughts on “本站的 HTTPS 配置篇”

Comments are closed.