现在主流浏览器都会鼓励网站添加HTTPS支持,如果还不与时俱进的话就会被它们在地址栏上各种羞辱。
个人博客买收费证书还是比较奢侈的,还好有 Let’s Encrypt 为我们提供了免费的解决方案。这里使用 acme.sh 脚本工具来处理证书申请。
安装 acme.sh
1
2
| yee@ubuntu:~$ sudo apt install socat
yee@ubuntu:~$ curl https://get.acme.sh | sh
|
会自动创建计划任务,也可以自定义,比如:
1
| 0 0 * * * "/home/yee/.acme.sh"/acme.sh --cron --home "/home/yee/.acme.sh" > /dev/null
|
验证域名所有权
泛域名签名只能通过DNS API模式验证,项目自带了主流的域名服务商的集成,这里以NameSilo为例。
上NameSilo API Manager页面生成API,然后:
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
| yee@ubuntu:~$ export Namesilo_Key="$NAMESILO_KEY"
yee@ubuntu:~$ alias acme.sh="/home/yee/.acme.sh/acme.sh"
yee@ubuntu:~$ acme.sh --issue --dns dns_namesilo --dnssleep 900 -d josta.me -d *.josta.me
[Wed Mar 14 11:13:26 CST 2018] Multi domain='DNS:josta.me,DNS:*.josta.me'
[Wed Mar 14 11:13:26 CST 2018] Getting domain auth token for each domain
[Wed Mar 14 11:13:27 CST 2018] Getting webroot for domain='josta.me'
[Wed Mar 14 11:13:28 CST 2018] Getting webroot for domain='*.josta.me'
[Wed Mar 14 11:13:28 CST 2018] Found domain api file: /home/yee/.acme.sh/dnsapi/dns_lexicon.sh
...
create_record: True
[Wed Mar 14 11:13:30 CST 2018] Sleep 960 seconds for the txt records to take effect
[Wed Mar 14 11:29:34 CST 2018] Verifying:josta.me
[Wed Mar 14 11:29:36 CST 2018] Success
[Wed Mar 14 11:29:36 CST 2018] Verifying:*.josta.me
[Wed Mar 14 11:29:39 CST 2018] Success
[Wed Mar 14 11:29:39 CST 2018] Removing DNS records.
[Wed Mar 14 11:29:39 CST 2018] Verify finished, start to sign.
[Wed Mar 14 11:29:40 CST 2018] Cert success.
-----BEGIN CERTIFICATE-----
MIIE/zCCA+egAwIBAgISA1V+J4qtPh412RQZ2hIZK1ipMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODAzMTQwMjI5MzlaFw0x
...
-----END CERTIFICATE-----
[Wed Mar 14 11:33:36 CST 2018] Your cert is in /home/yee/.acme.sh/josta.me/josta.me.cer
[Wed Mar 14 11:33:36 CST 2018] Your cert key is in /home/yee/.acme.sh/josta.me/josta.me.key
[Wed Mar 14 11:33:36 CST 2018] The intermediate CA cert is in /home/yee/.acme.sh/josta.me/ca.cer
[Wed Mar 14 11:33:36 CST 2018] And the full chain certs is there: /home/yee/.acme.sh/josta.me/fullchain.cer
|
可以把上面两个环境变量加入 /home/yee/.acme.sh/acme.sh.env
以便后续使用。
作者不推荐直接使用该目录下文件,所以还要执行一次安装:
1
2
3
| yee@ubuntu:~$ acme.sh --install-cert -d josta.me \
--key-file /etc/nginx/ssl/josta.me.key \
--fullchain-file /etc/nginx/ssl/fullchain.cer
|
acme项目比较活跃,为了能及时用上最新版本,可以设置脚本的自动更新,非常简单:
1
| yee@ubuntu:~$ acme.sh --upgrade --auto-upgrade
|
想取消的话可以执行:
1
2
3
4
5
6
7
8
9
10
11
12
13
| yee@ubuntu:~$ acme.sh --upgrade --auto-upgrade 0
[Fri Aug 25 21:01:56 CST 2017] Installing from online archive.
[Fri Aug 25 21:01:56 CST 2017] Downloading https://github.com/Neilpang/acme.sh/archive/master.tar.gz
[Fri Aug 25 21:01:58 CST 2017] Extracting master.tar.gz
[Fri Aug 25 21:01:58 CST 2017] Installing to /home/yee/.acme.sh
[Fri Aug 25 21:01:58 CST 2017] Installed to /home/yee/.acme.sh/acme.sh
[Fri Aug 25 21:01:58 CST 2017] Installing alias to '/home/yee/.bashrc'
[Fri Aug 25 21:01:58 CST 2017] OK, Close and reopen your terminal to start using acme.sh
[Fri Aug 25 21:01:58 CST 2017] Good, bash is found, so change the shebang to use bash as preferred.
[Fri Aug 25 21:01:58 CST 2017] OK
[Fri Aug 25 21:01:58 CST 2017] Install success!
[Fri Aug 25 21:01:58 CST 2017] Upgrade success!
|
此外,为了提升SSL评分,还需要解决Weak Diffie-Hellman问题,也即是要加大Diffie-Hellman交换密钥的预设质数的长度,运行:
1
| yee@ubuntu:~$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
|
生成 dhparam.pem
,等待几分钟就完成了(也可能几十分钟 :-( )。
Nginx配置调整
1
2
3
4
5
6
7
8
9
10
11
12
| server {
listen 443;
ssl on;
ssl_certificate /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/josta.me.key;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
# 取消了SSL v3支持
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 配置HSTS(`always`参数要求Nginx版本>=1.7.5)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY";
...
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| server {
listen 80 default_server;
listen [::]:80 default_server;
server_name www.josta.me josta.me;
server_tokens off;
access_log /dev/null;
if ($request_uri ~ \.(aspx|php|jsp|cgi)$) {
return 403;
}
if ($request_uri ~ "^/announce.*") {
return 403;
}
if ($request_uri ~ "^.*torrent.*") {
return 403;
}
return 301 https://$host;
}
|
最后 sudo systemctl reload nginx
就可以看效果了。
成果检验
1
| yee@ubuntu:~$ curl -s -D- https://josta.me | grep Strict
|
输出 strict-transport-security: max-age=31536000; includeSubDomains; preload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| yee@ubuntu:~$ curl -kI -v3 https://josta.me
* Rebuilt URL to: https://josta.me/
* Trying 77.77.77.77...
* TCP_NODELAY set
* Connected to josta.me (77.77.77.77) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* SSLv3 (OUT), TLS handshake, Client hello (1):
* SSLv3 (IN), TLS alert, Server hello (2):
* error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
* stopped the pause stream!
* Closing connection 0
curl: (35) error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
|
可以看到sslv3握手失败,满足预期
参考:
- 20180314更新: Let’s Encrypt已经支持签名泛域名证书,acme.sh项目也支持了ACME v2