使用验证DNS的方式申请证书

如果说你的网站要使用Let’s encrypt的话,当你无法使用A记录的方式添加 @www 时,而使用了 cname 记录添加,这种情况一般发生在使用 CDN 加速域名的时候会出现,例如你要加速 fangwenjun.com 和 www.fangwenjun.com 当你的源站也443端口加上证书也是采用的Let’s encrypt,就不能自动续期证书的,因为Let’s encrypt必须验证主域名的所有者,也就是说必须做 A 记录指向才可以申请和续签,而使用 CDN 一般得到的 IP 地址都是 CDN 厂商的代理 IP,并非你的真实 IP,这样就会导致升级续签会很麻烦,你不能享受Let’s encrypt的自动续签功能,做了计划任务到期续签,当你的源站证书到期后,你不得不修改 DNS 解析指向源站做 A 记录才能升级,否则超过90天源站的证书就会过期。

但是,在 GitHub 上我发现一个项目,叫 acme,项目地址
https://github.com/Neilpang/acme.sh,它是一个开源的项目,其实就是一个 sh 脚本,,它的强大之处就在于你即使是在你的本地 PC 上,同样可以申请Let’s encrypt证书,并且支持 DNS 的方式申请,而不占用你的 cname 和 A 记录,这样,哪怕你使用了 CDN 进行加速,也不必担心源站证书续签的问题,下面就简单演示下如何通过 DNS 的方式申请证书。

下载 acme

wget -O -  https://get.acme.sh | sh

脚本会自动安装,并且将文件安装在当前用户的主目录下 ~/.acme.sh/ 中,在这个目录中有一个 acme.sh 的文件,我们就是需要通过他来进行域名的申请。

设置别名

为了方便操作,我们设置下别名。

alias acme="~/.acme.sh/acme.sh"

你也可以把别名写在/etc/profile中或者/.bashrc中(根据你使用的shell来决定,比如我使用的是zsh,那么就是/.zshrc)

使用 DNS 的方式生成证书

好了下面我们开始了,我们使用 acme.sh --issue --dns -d domain.com 的方式来生成一个针对所申请域名的 TXT 解析记录和值,这样的目的是需要验证这个域名的的所有者是你本人,他会把这些信息保存在你的本地,后续不需要重复设置。

➜  .acme.sh acme.sh --issue --dns -d fangwenjun.com -d www.fangwenjun.com -d file.fangwenjun.com
[2017年 3月14日 星期二 22时56分55秒 CST] Registering account
[2017年 3月14日 星期二 22时57分03秒 CST] Registered
[2017年 3月14日 星期二 22时57分07秒 CST] Update success.
[2017年 3月14日 星期二 22时57分08秒 CST] ACCOUNT_THUMBPRINT='rtbrvOIhfSlomTtv1gUBS5ZByg9ORLs5bwl-ch1FK8Q'
[2017年 3月14日 星期二 22时57分08秒 CST] Creating domain key
[2017年 3月14日 星期二 22时57分08秒 CST] Multi domain='DNS:www.fangwenjun.com,DNS:file.fangwenjun.com'
[2017年 3月14日 星期二 22时57分08秒 CST] Getting domain auth token for each domain
[2017年 3月14日 星期二 22时57分08秒 CST] Getting webroot for domain='fangwenjun.com'
[2017年 3月14日 星期二 22时57分08秒 CST] Getting new-authz for domain='fangwenjun.com'
[2017年 3月14日 星期二 22时57分11秒 CST] The new-authz request is ok.
[2017年 3月14日 星期二 22时57分11秒 CST] Getting webroot for domain='www.fangwenjun.com'
[2017年 3月14日 星期二 22时57分11秒 CST] Getting new-authz for domain='www.fangwenjun.com'
[2017年 3月14日 星期二 22时57分15秒 CST] The new-authz request is ok.
[2017年 3月14日 星期二 22时57分15秒 CST] Getting webroot for domain='file.fangwenjun.com'
[2017年 3月14日 星期二 22时57分15秒 CST] Getting new-authz for domain='file.fangwenjun.com'
[2017年 3月14日 星期二 22时57分18秒 CST] The new-authz request is ok.
[2017年 3月14日 星期二 22时57分18秒 CST] Add the following TXT record:
[2017年 3月14日 星期二 22时57分18秒 CST] Domain: '_acme-challenge.fangwenjun.com'
[2017年 3月14日 星期二 22时57分18秒 CST] TXT value: 'wfcx_c5Gy-ru9DD3M4R8WtJs1tH_bxcSTMEZctdWpFM'
[2017年 3月14日 星期二 22时57分18秒 CST] Please be aware that you prepend _acme-challenge. before your domain
[2017年 3月14日 星期二 22时57分18秒 CST] so the resulting subdomain will be: _acme-challenge.fangwenjun.com
[2017年 3月14日 星期二 22时57分18秒 CST] Add the following TXT record:
[2017年 3月14日 星期二 22时57分18秒 CST] Domain: '_acme-challenge.www.fangwenjun.com'
[2017年 3月14日 星期二 22时57分18秒 CST] TXT value: 'jAsFVqh5S1fU9VsaNm0rAdG47AEsEAZVQwSoVtkUXzs'
[2017年 3月14日 星期二 22时57分18秒 CST] Please be aware that you prepend _acme-challenge. before your domain
[2017年 3月14日 星期二 22时57分18秒 CST] so the resulting subdomain will be: _acme-challenge.www.fangwenjun.com
[2017年 3月14日 星期二 22时57分18秒 CST] Add the following TXT record:
[2017年 3月14日 星期二 22时57分18秒 CST] Domain: '_acme-challenge.file.fangwenjun.com'
[2017年 3月14日 星期二 22时57分18秒 CST] TXT value: 'TAevmR4OZVbvqkGmc98hLq1mOJGA7_z29BMxa7BcIOI'
[2017年 3月14日 星期二 22时57分18秒 CST] Please be aware that you prepend _acme-challenge. before your domain
[2017年 3月14日 星期二 22时57分18秒 CST] so the resulting subdomain will be: _acme-challenge.file.fangwenjun.com
[2017年 3月14日 星期二 22时57分18秒 CST] Please add the TXT records to the domains, and retry again.
[2017年 3月14日 星期二 22时57分18秒 CST] Please add '--debug' or '--log' to check more details.
[2017年 3月14日 星期二 22时57分18秒 CST] See: https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh

设置 TXT,将你所得到的记录值和地址添加到域名解析中(这里只是演示,没有把www.fangwenjun.com和 file.fangwenjun.com的 TXT 值都添加,后面会造成申请这两个证书会失败)。

然后我们需要验证域名解析是否成功,验证 TXT 我们需要使用 dig domain -t TXT

然后我们可以申请证书了

➜  .acme.sh acme.sh --renew -d fangwenjun.com -d www.fangwenjun.com -d file.fangwenjun.com
[2017年 3月14日 星期二 22时59分47秒 CST] Renew: 'fangwenjun.com'
[2017年 3月14日 星期二 22时59分47秒 CST] Multi domain='DNS:www.fangwenjun.com,DNS:file.fangwenjun.com'
[2017年 3月14日 星期二 22时59分47秒 CST] Getting domain auth token for each domain
[2017年 3月14日 星期二 22时59分47秒 CST] Verifying:fangwenjun.com
[2017年 3月14日 星期二 23时00分01秒 CST] Success 
[2017年 3月14日 星期二 23时00分01秒 CST] Verifying:www.fangwenjun.com
[2017年 3月14日 星期二 23时00分12秒 CST] www.fangwenjun.com:Verify error:DNS problem: NXDOMAIN looking up TXT for _acme-challenge.www.fangwenjun.com
[2017年 3月14日 星期二 23时00分12秒 CST] Please add '--debug' or '--log' to check more details.
[2017年 3月14日 星期二 23时00分12秒 CST] See: https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh

提示 Succes 则表示成功了,下面的报错www.fangwenjun.com:Verify error:DNS problem: NXDOMAIN looking up TXT for _acme-challenge.www.fangwenjun.com中之所以失败,是因为当添加多个域名时候,必须要把每个 txt 记录都添加上,比如我要申请的域名fangwenjun.comwww.fangwenjun.comfile.fangwenjun.com,这个时候你需要根据上面的提示添加

[2017年 3月14日 星期二 22时57分18秒 CST] Domain: '_acme-challenge.fangwenjun.com'
[2017年 3月14日 星期二 22时57分18秒 CST] TXT value: 'wfcx_c5Gy-ru9DD3M4R8WtJs1tH_bxcSTMEZctdWpFM'

在域名fangwenjun.com下添加主机记录为_acme-challenge,记录值为wfcx_c5Gy-ru9DD3M4R8WtJs1tH_bxcSTMEZctdWpFM,类型选择TXT。

[2017年 3月14日 星期二 22时57分18秒 CST] Domain: '_acme-challenge.www.fangwenjun.com'
[2017年 3月14日 星期二 22时57分18秒 CST] TXT value: 'jAsFVqh5S1fU9VsaNm0rAdG47AEsEAZVQwSoVtkUXzs'

在域名fangwenjun.com下添加主机记录为_acme-challenge.www,记录值为jAsFVqh5S1fU9VsaNm0rAdG47AEsEAZVQwSoVtkUXzs,类型选择TXT。

[2017年 3月14日 星期二 22时57分18秒 CST] Domain: '_acme-challenge.file.fangwenjun.com'
[2017年 3月14日 星期二 22时57分18秒 CST] TXT value: 'TAevmR4OZVbvqkGmc98hLq1mOJGA7_z29BMxa7BcIOI'

在域名fangwenjun.com下添加主机记录为_acme-challenge.file,记录值为TAevmR4OZVbvqkGmc98hLq1mOJGA7_z29BMxa7BcIOI,类型选择TXT。

以此类推,你需要几个ssl域名就添加几条TXT记录,注意不要复制错。

最后,申请的证书在~/acme.sh目录下

➜  .acme.sh ls
account.conf   acme.sh        acme.sh.env    ca             deploy         dnsapi         fangwenjun.com http.header
➜  .acme.sh cd fangwenjun.com
➜  fangwenjun.com ls
fangwenjun.com.conf     fangwenjun.com.csr      fangwenjun.com.csr.conf fangwenjun.com.key

配置nginx

1.在nginx的路径中创建一个ssl目录,并赋予其nginx进程的访问权限

mkdir -p /usr/local/nginx/ssl && chown -R www:www /usr/local/nginx/ssl

2.然后,在/usr/bin目录下创建一个脚本updatessl,内容如下

#!/bin/bash
/root/.acme.sh/acme.sh  --installcert  -d  fangwenjun.com --keypath   /usr/local/nginx/ssl/fangwenjun.com.key --fullchainpath /usr/local/nginx/ssl/fangwenjun.com.cer --reloadcmd  "/etc/init.d/nginx restart"

3.赋予其可执行权限

chmod +x /usr/bin/updatessl

4.将其加入到计划任务中

0 8 * 1 * root "/usr/bin/updatessl > /dev/null

5.在你的nginx.conf或虚拟主机的配置文件中找到修改证书的路径

server{
        listen 443 ssl http2 default_server;
        server_name www.fangwenjun.com fangwenjun.com;
        index index.html index.htm index.php;
        root  /home/wwwroot/default;
        ssl on;
        ssl_certificate /usr/local/nginx/ssl/fangwenjun.com.cer;
        ssl_certificate_key /usr/local/nginx/ssl/fangwenjun.com.key;
}

如希望80端口访问也跳到https 去,可以在加一个 server,使用 rewrite 进行跳转。

server {
    listen  80 default_server;
    server_name  www.fangwenjun.com fangwenjun.com;

    rewrite ^(.*)$  https://$host$1 permanent;
}

自动更新

acme会自动加入一条计划任务,你可以使用crontab -e 查看

0 2 14 * * `/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null`
0 3 14 * * root `/usr/bin/updatessl > /dev/null`

以上操作后,每14天的凌晨2点会更新acme和续签证书 /root/.acme.sh --renew-all --force,然后14天的3点会把续签好的证书拷贝到nginx的ssl目录中并重启nginx。