CentOS 7 使用 acme.sh 自动申请免费 SSL 证书

Let’s Encrypt is a free, automated, and open Certificate Authority.

acme.sh 实现了 acme 协议, 可以从 Let’s Encrypt 生成免费的证书并自动更新,支持多域名和泛域名。

安装配置 acme.sh

安装 acme.sh

下载安装 acme.sh

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

重新登录 SSH,查看已安装的 acme.sh 的版本号:

acme.sh -v

https://github.com/Neilpang/acme.sh
v2.7.9

申请证书

生成证书需要验证域名所有权,可通过 DNS 设置,在域名上添加一条 TXT 解析记录来验证域名所有权,需要使用 Automatic DNS API 来完成证书的自动申请。

前往自己的 DNS 服务商创建 API Key ,得到 API Key ID 和 API key Secret。

查看 How to use DNS API 找到自己的 DNS 服务商对应的命令,如阿里云的:

# 换成自己的 API Key ID 和 API Key Secret
export Ali_Key="ZbRj8467md0lKyUGfWP"
export Ali_Secret="fWPb9yUGgd4LkKRHWKglMZ7md0j846"

# 换成自己的域名,多个域名添加多个 "-d <doman>",支持泛域名
acme.sh --issue --dns dns_ali -d imzhengfei.com -d *.imzhengfei.com

注意:

  • 不同 DNS 服务商的变量名,命令也不一样,务必前往 How to use DNS API 找到自己 DNS 服务商对应的代码。
  • 生成的证书会以最前面的那个域名来命名,后面的配置会用到。
  • 支持多个顶级域名和泛域名混合,但是都必须在同一处 DNS 服务商处解析。
  • 阿里云推荐使用 “子用户AccessKey”,然后只给予子用户 “AliyunDNSFullAccess“ 权限。

[2018年 04月 30日 星期一 00:05:34 CST] Registering account
[2018年 04月 30日 星期一 00:05:36 CST] Registered
[2018年 04月 30日 星期一 00:05:36 CST] ACCOUNT_THUMBPRINT='m5OMy9olafE-oDjpp8GnmVZeee6V8VISFGRY8zsmods'
[2018年 04月 30日 星期一 00:05:36 CST] Creating domain key
[2018年 04月 30日 星期一 00:05:36 CST] The domain key is here: /root/.acme.sh/imzhengfei.com/imzhengfei.com.key
[2018年 04月 30日 星期一 00:05:36 CST] Multi domain='DNS:imzhengfei.com,DNS:.imzhengfei.com'
[2018年 04月 30日 星期一 00:05:36 CST] Getting domain auth token for each domain
[2018年 04月 30日 星期一 00:05:38 CST] Getting webroot for domain='imzhengfei.com'
[2018年 04月 30日 星期一 00:05:38 CST] Getting webroot for domain='
.imzhengfei.com'
[2018年 04月 30日 星期一 00:05:38 CST] Found domain api file: /root/.acme.sh/dnsapi/dns_ali.sh
[2018年 04月 30日 星期一 00:05:39 CST] Found domain api file: /root/.acme.sh/dnsapi/dns_ali.sh
[2018年 04月 30日 星期一 00:05:41 CST] Sleep 120 seconds for the txt records to take effect
[2018年 04月 30日 星期一 00:07:43 CST] Verifying:imzhengfei.com
[2018年 04月 30日 星期一 00:07:46 CST] Success
[2018年 04月 30日 星期一 00:07:46 CST] Verifying:*.imzhengfei.com
[2018年 04月 30日 星期一 00:07:49 CST] Success
[2018年 04月 30日 星期一 00:07:49 CST] Removing DNS records.
[2018年 04月 30日 星期一 00:07:54 CST] Verify finished, start to sign.
[2018年 04月 30日 星期一 00:07:56 CST] Cert success.
-----BEGIN CERTIFICATE-----
…...
-----END CERTIFICATE-----
[2018年 04月 30日 星期一 00:07:56 CST] Your cert is in /root/.acme.sh/imzhengfei.com/imzhengfei.com.cer
[2018年 04月 30日 星期一 00:07:56 CST] Your cert key is in /root/.acme.sh/imzhengfei.com/imzhengfei.com.key
[2018年 04月 30日 星期一 00:07:56 CST] The intermediate CA cert is in /root/.acme.sh/imzhengfei.com/ca.cer
[2018年 04月 30日 星期一 00:07:56 CST] And the full chain certs is there: /root/.acme.sh/imzhengfei.com/fullchain.cer

中间会倒计时等待两分钟等待解析生效,申请成功。

保存证书

创建保存证书的目录:

# 换成自己的目录名称
mkdir -p /etc/nginx/ssl

保存证书并重启 nginx:

# 换成自己的域名
acme.sh --install-cert -d imzhengfei.com \
        --key-file /etc/nginx/ssl/imzhengfei.com.key \
        --fullchain-file /etc/nginx/ssl/fullchain.cer \
        --reloadcmd "systemctl --force restart nginx"

注意:

  • 最后一行的命令是 CentOS 7 强制重启 nginx 的命令,如果是其他系统或者其他反向代理工具,请自行更换命令,且必须使用强制重启模式(否则证书更新时无法刷新证书)。
  • Let’s Encrypt 证书有效期为 90 天,目前在 60 天(今后有可能会缩短这个时间)后,acme.sh 会自动执行以上命令,重新申请证书,并强制重启 nginx。

[2018年 04月 30日 星期一 00:29:04 CST] Installing key to:/etc/nginx/ssl/imzhengfei.com/imzhengfei.com.key
[2018年 04月 30日 星期一 00:29:04 CST] Installing full chain to:/etc/nginx/ssl/imzhengfei.com/fullchain.cer
[2018年 04月 30日 星期一 00:29:04 CST] Run reload cmd: systemctl --force restart nginx
[2018年 04月 30日 星期一 00:29:04 CST] Reload success

自动更新 acme.sh

目前由于 acme 协议和 letsencrypt CA 都在频繁的更新,因此 acme.sh 也经常更新以保持同步,可以设置自动更新:

acme.sh --upgrade --auto-upgrade

[2018年 04月 30日 星期一 00:30:49 CST] Installing from online archive.
[2018年 04月 30日 星期一 00:30:49 CST] Downloading https://github.com/Neilpang/acme.sh/archive/master.tar.gz
[2018年 04月 30日 星期一 00:30:52 CST] Extracting master.tar.gz
[2018年 04月 30日 星期一 00:30:52 CST] It is recommended to install socat first.
[2018年 04月 30日 星期一 00:30:52 CST] We use socat for standalone server if you use standalone mode.
[2018年 04月 30日 星期一 00:30:52 CST] If you don't use standalone mode, just ignore this warning.
[2018年 04月 30日 星期一 00:30:52 CST] Installing to /root/.acme.sh
[2018年 04月 30日 星期一 00:30:52 CST] Installed to /root/.acme.sh/acme.sh
[2018年 04月 30日 星期一 00:30:52 CST] Good, bash is found, so change the shebang to use bash as preferred.
[2018年 04月 30日 星期一 00:30:52 CST] OK
[2018年 04月 30日 星期一 00:30:52 CST] Install success!
[2018年 04月 30日 星期一 00:30:52 CST] Upgrade success!

如需手动更新:

acme.sh --upgrade

如需关闭自动更新:

acme.sh --upgrade --auto-upgrade 0

nginx 配置

生成 DH 密钥参数

这一步有可能会消耗很长时间,直到出现两个 * 才会结束:

# 换成自己保存证书的路径
openssl dhparam 2048 -out /etc/nginx/ssl/dhparam.pem
This is going to take a long time
......................................++*++*

SSL 配置

/etc/nginx/conf.d/ 目录下创建 SSL 配置文件:

vim /etc/nginx/conf.d/ssl.conf

插入以下配置:

# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/imzhengfei.com.key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;

# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/nginx/ssl/dhparam.pem;

# intermediate configuration. tweak to your needs.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;

# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
resolver 223.5.5.5 223.6.6.6 114.114.114.114 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 10s;

# HSTS (ngx_http_headers_module is required) (31536000 seconds ≈ 1 year)
add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains; preload';

# only allow frames form same origin
add_header X-Frame-Options SAMEORIGIN;

# no MIME-sniffing for Content-Type
add_header X-Content-Type-Options nosniff;

# hide nginx version
server_tokens off;

注意:

  • ssl_certificatessl_certificate_keyssl_dhparam 换成自己文件的路径。
  • 这种单独的配置文件将直接被 nginx.conf 加载,在 http 域下生效,所有 server 都共享相同的 SSL 配置。如果想每个 server 单独配置,则添加配置代码到对应的 server 域下面。

Server 配置

/etc/nginx/conf.d/ 目录下创建网站的配置文件:

vim /etc/nginx/conf.d/imzhengfei.com.conf

插入配置:

# imzhengfei.com
server {
  listen 80;
  server_name imzhengfei.com;
  return 301 https://$http_host$request_uri;
}

# https for imzhengfei.com
server {
  listen 443;
  ssl on;
  server_name imzhengfei.com;
  root /home/wwwroot/imzhengfei.com;
  index index.html;
}

注意: 以上是一个简单的静态页面代理配置实例,http 将被永久重定向到 https,根据需要修改成自己的配置。

强制重启 nginx:

systemctl --force restart nginx

防火墙设置

查看 https 服务是否已经永久启用:

firewall-cmd --permanent --query-service=https

查看 443/tcp 端口是否已被永久添加到默认区域:

firewall-cmd --permanent --query-port=443/tcp

如果都没有,则添加 https 服务(443/tcp):

firewall-cmd --permanent --add-service=https

查看下次重启(防火墙重新加载、服务器重启或者系统重启)之后永久生效的服务:

firewall-cmd --permanent --list-service

http https ssh

重新加载防火墙规则:

firewall-cmd --reload

注意: 阿里云主机需要在安全组规则中添加入方向的 443/tcp 端口。

SSL 安全检测

检测地址:https://www.ssllabs.com/ssltest/

输入域名,正常情况下检测结果应为 A+

参考文献