0x01 前言

Let’s Encrypt项目开展一年多了,很早以前已经支持泛域名证书的签发,而我的博客从该项目正式运行的时候也切换到Let’s Encrypt的数字证书。

刚开始的时候签发证书比较繁琐,需要自己手敲命令,但后来有位大佬创建了acme.sh这个项目,以下是该项目的GitHub地址:

通过访问acme.sh一样可以打开该项目的GitHub页面噢。因为该项目是国人创建的,所以会有中文版本的说明文档。

而今天这篇文章只是记录下我日常使用的情况,主要结合阿里云的DNS服务申请和续签免费的Let’s Encrypt数字证书。因为我使用的功能比较单一,所以文章里没有其他高级功能的部分,如果有需要,请留意该项目的中文说明部分。如果以后有需求,我会撰写文章,额外说明。

0x02 准备

Let’s Encrypt只支持DV证书的签发,也就是通过验证域名所有权,然后签发该域名的证书。它支持两种验证方式,一种是通过HTTP的方式验证,另一种是通过DNS的方式验证,而今天要讲的就是第二种方式。

首先得准备一个可以使用阿里云DNS解析服务的阿里云账号。阿里云的DNS解析服务是免费的,但免费版本的TTL最小为10分钟,如果需要更小的TTL值,则需要购买升级服务。相关咨询可以参考以下文章:

但Let’s Encrypt验证DNS对TTL并没有要求,用免费版的阿里云DNS解析服务是可以的。

紧接着需要将你的域名解析权赋予阿里云,首先在阿里云的DNS解析服务中添加你的域名:

域名添加完成后会给出两个DNS服务器的域名,这时候需要在你购买域名的厂商中将域名的DNS服务器修改为给出的DNS服务器即可。

稍等片刻,当页面中出现绿色勾勾,则说明DNS服务器切换完成,你域名正由阿里云提供解析服务。

接下来要准备acme.sh源码,直接使用git clone即可将源码克隆到本地:

[root@b695a3 ~]# git clone https://github.com/Neilpang/acme.sh.git

在签发证书前还得准备阿里云账户的API key,打开以下地址并创建AccessKey即可:

注意!阿里云支持子账户功能,为了提高安全性,请参考阿里云的文档,创建子账户后再创建API key,但这不是必须操作的。

创建完成后将AccessKey ID与Access Key Secret记下来备用。

0x03 acme.sh

我们已经准备好一切,接下来先安装acme.sh到本地,进入源码文件夹并执行以下命令即可:

# 进入文件夹
[root@b695a3 ~]# cd acme.sh/

# 安装
[root@b695a3 acme.sh]# ./acme.sh --install
[Sun Jan 27 19:23:03 HKT 2019] It is recommended to install socat first.
[Sun Jan 27 19:23:03 HKT 2019] We use socat for standalone server if you use standalone mode.
[Sun Jan 27 19:23:03 HKT 2019] If you don't use standalone mode, just ignore this warning.
[Sun Jan 27 19:23:03 HKT 2019] Installing to /root/.acme.sh
[Sun Jan 27 19:23:03 HKT 2019] Installed to /root/.acme.sh/acme.sh
[Sun Jan 27 19:23:03 HKT 2019] Installing alias to '/root/.bashrc'
[Sun Jan 27 19:23:03 HKT 2019] OK, Close and reopen your terminal to start using acme.sh
[Sun Jan 27 19:23:03 HKT 2019] Installing alias to '/root/.cshrc'
[Sun Jan 27 19:23:03 HKT 2019] Installing alias to '/root/.tcshrc'
[Sun Jan 27 19:23:03 HKT 2019] Installing cron job
no crontab for root
no crontab for root
[Sun Jan 27 19:23:03 HKT 2019] Good, bash is found, so change the shebang to use bash as preferred.
[Sun Jan 27 19:23:03 HKT 2019] OK

默认情况下,acme.sh以隐藏文件夹的形式安装在用户的home目录下,而我是用root用户,所以它在这里:

[root@b695a3 acme.sh]# ll /root/.acme.sh/
total 188
-rw-r--r-- 1 root root     96 Jan 27 19:23 account.conf
-rwxr-xr-x 1 root root 169557 Jan 27 19:23 acme.sh
-rw-r--r-- 1 root root     78 Jan 27 19:23 acme.sh.csh
-rw-r--r-- 1 root root     78 Jan 27 19:23 acme.sh.env
drwxr-xr-x 2 root root   4096 Jan 27 19:23 deploy
drwxr-xr-x 2 root root   4096 Jan 27 19:23 dnsapi

另外,它还会创建一个定时任务,通过以下命令即可查看:

[root@b695a3 acme.sh]# crontab -e
3 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

定时任务会在每天0点3分调用acme.sh程序,以检查证实是否过期,是否需要续签等。这个定时任务的时间是随机的,但不影响主要功能。

完成安装后先来准备脚本,这个脚本只需要执行一次。执行后,这些信息会记录在相关目录中,后续的执行将自动执行:

# 首先执行以下两行
export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export Ali_Secret="jlsdflanljkljlfdsaklkjflsa"

# 而后申请签发证书
acme.sh --issue --dns dns_ali -d m4d3bug.com -d *.m4d3bug.com

将之前步骤中准备好的阿里云API key填写到上面命令的中,并在终端中执行,执行后并不会有内容返还:

然后准备签发证书的命令,因为是签发,所以要使用“–issue”参数;指明使用“dns_ali”作为验证方式;后面跟着的“-d”为指定证书中的域名,这里有一点需要注意的:如果证书中只包含泛域名,那么签发出来的证书是没有根域的。所以需要额外添加一个根域,如上面的命令所示。

其他厂商的DNS API信息请参考以下链接:

完成后即可到acme.sh的安装目录中执行:

# 进入文件夹
[root@b695a3 ~]# cd /root/.acme.sh/

# 执行命令
[root@b695a3 .acme.sh]# ./acme.sh --issue --dns dns_ali -d m4d3bug.com -d *.m4d3bug.com
[Sun Jan 27 19:39:36 HKT 2019] Registering account
[Sun Jan 27 19:39:37 HKT 2019] Registered
[Sun Jan 27 19:39:37 HKT 2019] ACCOUNT_THUMBPRINT='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
[Sun Jan 27 19:39:37 HKT 2019] Creating domain key
[Sun Jan 27 19:39:37 HKT 2019] The domain key is here: /root/.acme.sh/m4d3bug.com/m4d3bug.com.key
[Sun Jan 27 19:39:37 HKT 2019] Multi domain='DNS:m4d3bug.com,DNS:*.m4d3bug.com'
[Sun Jan 27 19:39:37 HKT 2019] Getting domain auth token for each domain
[Sun Jan 27 19:39:40 HKT 2019] Getting webroot for domain='m4d3bug.com'
[Sun Jan 27 19:39:40 HKT 2019] Getting webroot for domain='*.m4d3bug.com'
[Sun Jan 27 19:39:40 HKT 2019] Found domain api file: /root/.acme.sh/dnsapi/dns_ali.sh
[Sun Jan 27 19:39:42 HKT 2019] Found domain api file: /root/.acme.sh/dnsapi/dns_ali.sh
[Sun Jan 27 19:39:45 HKT 2019] Sleep 120 seconds for the txt records to take effect

在执行命令后,程序会调用阿里云的API,在DNS中添加以下内容:

然后程序会等待120秒,以便让DNS生效,而后再调用Let’s Encrypt的API进行验证与证书的签发工作:

如果一切正常,验证通过之后,会完成证书签发的工作,最后会将DNS中用于验证域名所有权的TXT解析记录删除:

0x04 使用

完成签发后,再看看acme.sh安装目录中,会发现以相关域名命名的文件夹:

[root@b695a3 .acme.sh]# ll /root/.acme.sh/
total 192
-rw-r--r-- 1 root root    251 Jan 27 19:42 account.conf
-rwxr-xr-x 1 root root 169557 Jan 27 19:23 acme.sh
-rw-r--r-- 1 root root     78 Jan 27 19:23 acme.sh.csh
-rw-r--r-- 1 root root     78 Jan 27 19:23 acme.sh.env
drwxr-xr-x 3 root root     42 Jan 27 19:39 ca
drwxr-xr-x 2 root root   4096 Jan 27 19:23 deploy
drwxr-xr-x 2 root root   4096 Jan 27 19:23 dnsapi
-rw-r--r-- 1 root root    395 Jan 27 19:42 http.header
drwxr-xr-x 2 root root    162 Jan 27 19:42 m4d3bug.com

域名文件夹中有以下文件:

[root@b695a3 .acme.sh]# ll /root/.acme.sh/m4d3bug.com/
total 28
-rw-r--r-- 1 root root 1648 Jan 27 19:42 ca.cer
-rw-r--r-- 1 root root 3567 Jan 27 19:42 fullchain.cer
-rw-r--r-- 1 root root 1919 Jan 27 19:42 m4d3bug.com.cer
-rw-r--r-- 1 root root  536 Jan 27 19:42 m4d3bug.com.conf
-rw-r--r-- 1 root root  989 Jan 27 19:39 m4d3bug.com.csr
-rw-r--r-- 1 root root  224 Jan 27 19:39 m4d3bug.com.csr.conf
-rw-r--r-- 1 root root 1675 Jan 27 19:39 m4d3bug.com.key

相关文件的用途如下:

  • ca.cer:Let’s Encrypt的中级证书
  • fullchain.cer:包含中级证书的域名证书
  • m4d3bug.com.cer:无中级证书的域名证书
  • m4d3bug.com.conf:该域名的配置文件
  • m4d3bug.com.csr:该域名的CSR证书请求文件
  • m4d3bug.com.csr.conf:该域名的CSR请求文件的配置文件
  • m4d3bug.com.key:该域名证书的私钥

因为我主要将证书用在nginx,所以需要用到包含中级证书的域名证书与私钥,而其他文件请不要修改,同时请保护好acme.sh安装目录中的所有文件,一旦泄露请及时更换API key、吊销证书并且注销Let’s Encrypt账号。

接下来通过nginx进行测试,以下是配置文件:

server {
  listen                     443 ssl http2;
  server_name                m4d3bug.com;

  ssl_certificate            /usr/local/nginx/ssl/m4d3bug.com.crt;
  ssl_certificate_key        /usr/local/nginx/ssl/m4d3bug.com.key;
  ssl_buffer_size            16k;
  ssl_protocols              TLSv1.1 TLSv1.2 TLSv1.3;
  ssl_ecdh_curve             X25519:P-256:P-384:P-224:P-521;
  ssl_ciphers                TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
  ssl_prefer_server_ciphers  on;
  ssl_session_timeout        3h;
  ssl_stapling               on;
  ssl_session_tickets        on;

  access_log                 /var/log/nginx/access.log main;

  add_header                 Strict-Transport-Security "max-age=31536000; preload; includeSubDomains" always;
  add_header                 X-Frame-Options SAMEORIGIN;

  index                      index.php index.html;

  location / {
    root                     /usr/local/nginx/html;
  }
}

通过浏览器打开,即可检查证书的信息:

0x05 结语

Let’s Encrypt签发的证书有效期为90天,也就是说一年至少要更换4次。这是完全不可接受的,要是忘记不就完蛋了?

还好acme.sh支持自动部署,和调用脚本。这时候可以自行撰写脚本,将证书分发到各个节点,这个有时间再写文章了。