(不必读本文了,建议去读https://briteming.blogspot.com/2018/10/acmeshletsencryptssl.html 就够了)
现在主流浏览器都会鼓励网站添加HTTPS支持,如果还不与时俱进的话就会被它们在地址栏上各种羞辱。 个人博客买收费证书还是比较奢侈的,还好有 Let’s Encrypt 为我们提供了免费的解决方案。这里使用 acme.sh 脚本工具来处理证书申请。
安装 acme.sh
yee@ubuntu:~$ sudo apt install socat
yee@ubuntu:~$ curl https://get.acme.sh | sh
会自动创建计划任务.如果此命令自动创建计划任务失败,我们可以去自定义,比如:
0 0 * * * "/home/yee/.acme.sh"/acme.sh --cron --home "/home/yee/.acme.sh" > /dev/null
验证域名所有权
yee@ubuntu:~$ sudo apt install python-pip
yee@ubuntu:~$ pip install dns-lexicon
上NameSilo API Manager页面生成API,然后:
yee@ubuntu:~$ export PROVIDER=namesilo yee@ubuntu:~$ export LEXICON_NAMESILO_TOKEN="$NAMESILO_API" yee@ubuntu:~$ /home/yee/.acme.sh/acme.sh --issue -d domain.com -d www.domain.com --dns dns_lexicon --dnssleep
[Thu Aug 3 10:28:23 CST 2017] Single domain='domain.com'
[Thu Aug 3 10:28:23 CST 2017] Getting domain auth token for each domain [Thu Aug 3 10:28:23 CST 2017] Getting webroot for domain='domain.com'
[Thu Aug 3 10:28:23 CST 2017] Getting new-authz for domain='domain.com'
[Thu Aug 3 10:28:27 CST 2017] The new-authz request is ok. [Thu Aug 3 10:28:27 CST 2017] domain.com is already verified, skip http-01. [Thu Aug 3 10:28:27 CST 2017] Verify finished, start to sign. [Thu Aug 3 10:28:29 CST 2017] Cert success. -----BEGIN CERTIFICATE----- MIIE/TCCA+WgAwIBAgISA6IG6Ds76q7W6h/qoGIk+pb4MA0GCSqGSIb3DQEBCwUA MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzA4MDMxMzQ5MDBaFw0x ... -----END CERTIFICATE----- [Thu Aug 3 10:28:29 CST 2017] Your cert is in /home/yee/.acme.sh/domain.com/domain.com.cer [Thu Aug 3 10:28:29 CST 2017] Your cert key is in /home/yee/.acme.sh/domain.com/domain.com.key [Thu Aug 3 10:28:30 CST 2017] The intermediate CA cert is in /home/yee/.acme.sh/domain.com/ca.cer [Thu Aug 3 10:28:30 CST 2017] And the full chain certs is there: /home/yee/.acme.sh/domain.com/fullchain.cer
作者不推荐直接使用该目录下文件,所以还要执行一次安装:
yee@ubuntu:~$ acme.sh --install-cert -d domain.com \
--key-file /etc/nginx/ssl/domain.com.key \
--fullchain-file /etc/nginx/ssl/domain.com.cer
acme项目比较活跃,为了能及时用上最新版本,可以设置脚本的自动更新,非常简单:
yee@ubuntu:~$ acme.sh --upgrade --auto-upgrade
想取消的话可以执行:
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交换密钥的预设质数的长度,运行:
yee@ubuntu:~$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
生成
dhparam.pem
,等待几分钟就完成了(也可能几十分钟 :-( )。Nginx配置调整
- 修改Nginx站点设置
server { listen 443; ssl on; ssl_certificate /etc/nginx/ssl/domain.com.cer;
ssl_certificate_key /etc/nginx/ssl/domain.com.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"; ...
- 增加HTTP的301跳转:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name www.domain.com domain.com;
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
就可以看效果了。成果检验
- 检查HSTS状态:
yee@ubuntu:~$ curl -s -D- https://domain.com | grep Strict
输出
strict-transport-security: max-age=31536000; includeSubDomains; preload
- 确认下SSL v3是否被关闭
yee@ubuntu:~$ curl -kI -v3 https://domain.com * Rebuilt URL to: https://domain.com * Trying 77.77.77.77... * TCP_NODELAY set * Connected to domain.com (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握手失败,满足预期
- SSL Server Test 检查,评分达到A+级。
参考:
- How To Secure Nginx with Let’s Encrypt on Ubuntu 16.04
- HTTP Strict Transport Security (HSTS) and NGINX
- 其它域名服务商的API支持情况可以查看 Automatic DNS API integration
安装 acme.sh
curl https://get.acme.sh | sh
虽然 LE 证书有效期只有三个月,但是在证书过期前 acme.sh 会自动进行续期,所以不需担心.