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