Total Pageviews

Saturday, 3 December 2016

使用acme.sh签发Let's Encrypt的免费SSL证书

(不必读本文了,建议去读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

验证域名所有权

我是在NameSilo注册的域名,支持通过lexicon dns api使用1,先安装lexicon
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握手失败,满足预期
参考:
------------------------------------------------------------------

安装 acme.sh
curl https://get.acme.sh | sh  

虽然 LE 证书有效期只有三个月,但是在证书过期前 acme.sh 会自动进行续期,所以不需担心.