Nginx 系列(四)——添加 SSL

Nginx 全系列

无论是为了安全还是为了B格(地址栏的小锁),我们都很有必要给自己的网站加 SSL,并使用 HTTPS 访问。

前提:拥有域名

没有的话一切就无从谈起了。

使用 acme.sh 获取证书

以下主要参考官方说明

下载安装

1
curl  https://get.acme.sh | sh

申请证书

1
acme.sh --issue -d mydomain.com --nginx --ocsp
  • 上述命令包含了 OCSP 协议的支持。
  • 若同时申请多个域名,可以写多个 -d <domain>
  • 申请通配符证书需要使用 DNS API,以后再补。

安装证书

1
2
3
4
acme.sh --installcert -d  <domain>.com \
--key-file /path/to/cert/<domain>.key \
--fullchain-file /path/to/cert/<domain>.crt \
--ca-file /path/to/cert/ca.crt

在 Nginx 中配置证书

以下为推荐配置,参考了 gavinhungry/nginx-tls.conf。大部分内容照抄即可,只需要设置第 6 行的主机名和第 13-15 行的证书,并下载推荐使用的 DH 密钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
server {
# 监听
listen 443 ssl http2 spdy;

# 主机名
server_name example.com www.example.com;

############
## SSL 设置
############

# 设置证书
ssl_certificate /path/to/cert/<domain>.crt;
ssl_certificate_key /path/to/cert/<domain>.key;
ssl_trusted_certificate /path/to/cert/ca.crt;

# D-H 交换密钥
## 推荐使用 https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe4096
ssl_dhparam /path/to/cert/ffdhe4096.pem;

# 设置连接协议、加密方式
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:ECDH+AESGCM:ECDH+AES256:DH+AESGCM:DH+AES256:RSA+AESGCM:!aNULL:!eNULL:!LOW:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
ssl_ecdh_curve X25519:P-256:P-384;

# 缓存和会话设置
ssl_buffer_size 4k;
ssl_session_cache shared:TLS:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 114.114.114.114 223.5.5.5 valid=300s;
resolver_timeout 10s;

# TLS 1.3 0-RTT
ssl_early_data on;
proxy_set_header Early-Data $ssl_early_data;

# 关闭 Nginx 版本显示
server_tokens off;

# HSTS
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload' always;

############
## 其他设置
############
location ...
}

自动跳转

通过 HTTP 访问时,返回 301 跳转到 HTTPS

1
2
3
4
5
6
server {
listen 80;
server_name example.com www.example.com;

rewrite ^(.*)$ https://$host$1 permanent;
}

关于 strict-SNI

此功能需要至少两个开启 HTTPS 的 server,所以对于只托管了一个网站的情况需要再添加一个启用 SSL 的虚拟主机作为 fake server。幸运的是它对证书等具体配置没有要求,证书随便生成一个或者直接用真实主机的也可以:

1
2
3
4
5
6
7
8
9
10
server {
listen 443 ssl;

server_name localhost;

ssl_certificate /path/to/cert/<domain>.crt;
ssl_certificate_key /path/to/cert/<domain>.key;

return 444;
}

测试配置:

本地检验

1
sudo nginx -t

生效

1
sudo nginx -s reload

测试

https://ssllabs.com