部署Let’s Encrypt的证书

最近想用TLS加强一下梯子的安全性,断断续续折腾了几天,遇到了不少兼容性问题,踩了不少坑,终于部署好了Let’s Encrypt的证书,在这里记录一下自己部署Let’s Encrypt的过程。

安装Certbot客户端

VPS是Debian8+Nginx,根据官网的教程,只要apt-get install certbot安装好客户端之后certbot certonly就能申请到证书,可惜我在第一步就出了岔子:

[email protected]:~# apt-get install certbot
正在读取软件包列表... 完成
正在分析软件包的依赖关系树
正在读取状态信息... 完成
有一些软件包无法被安装。如果您用的是 unstable 发行版,这也许是
因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件
包尚未被创建或是它们已被从新到(Incoming)目录移出。
下列信息可能会对解决问题有所帮助:

下列软件包有未满足的依赖关系:
 certbot : 依赖: python-certbot (= 0.10.2-1~bpo8+1) 但是它将不会被安装
E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

certbot有一个依赖python-cryptography,要求版本>=7.0,然而apt-get里的最高版本只有6.1,使用pip手动安装,apt-get又无法识别,只能另寻他路。
搜索了一下,看到这篇文章,EFF官方还搞了一个客户端certbot-auto,wget下来之后运行自动下载依赖,这次安装倒没有碰到什么兼容性问题。

wget https://dl.eff.org/certbot-auto
chmod a+x ./certbot-auto
./certbot-auto --help

获取证书

Let’s Encrypt在2018年1月已经正式支持通配符证书,可以覆盖所有的一级子域名,非常方便,只要把命令里的domain前面加个通配符*就可以了,我申请的就是这个,不过这个证书只支持DNS验证,如果要自动验证的话麻烦不少。

./certbot_auto certonly -d *.thezrj.com,thezrj.com

配置nginx

在nginx的虚拟主机的配置文件里加上443端口和公钥私钥的地址,重启一下nginx,证书就部署完成了。

    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    #ssl on;
    ssl_certificate /etc/letsencrypt/live/thezrj.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/thezrj.com/privkey.pem;

自动续期

Let’s Encrypt的证书有效期只有三个月,手动续期的话很麻烦也很容易忘了,便试着部署了一下自动续期,把几个模式都试了一下,总是爆出红字错误:

Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA. You may need to use an authenticator plugin that can do challenges over DNS.

查了一下官网手册,才知道通配符证书不能使用文件验证(http-01和tls-sni-01),只能使用dns验证,更坑的是certbot-auto竟然不包含dns插件,只能自己挂sh脚本,幸好手册上已经有cloudflare的脚本,但还不能直接用,脚本的正则竟然不能匹配没有前缀的裸域名,改了一下终于把自动dns验证做好了。

#!/bin/bash

# 在 https://dash.cloudflare.com/profile 获取API_KEY
API_KEY=
EMAIL=

# Strip only the top domain to get the zone id
# 此正则表达式不能适配裸域名
#DOMAIN=$(expr match "$CERTBOT_DOMAIN" '.*\.\(.*\..*\)')
DOMAIN=$CERTBOT_DOMAIN

# Get the Cloudflare zone id
ZONE_EXTRA_PARAMS="status=active&page=1&per_page=20&order=status&direction=desc&match=all"
ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$DOMAIN&$ZONE_EXTRA_PARAMS" \
     -H     "X-Auth-Email: $EMAIL" \
     -H     "X-Auth-Key: $API_KEY" \
     -H     "Content-Type: application/json" | python -c "import sys,json;print(json.load(sys.stdin)['result'][0]['id'])")

# Create TXT record
CREATE_DOMAIN="_acme-challenge.$CERTBOT_DOMAIN"
RECORD_ID=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
     -H     "X-Auth-Email: $EMAIL" \
     -H     "X-Auth-Key: $API_KEY" \
     -H     "Content-Type: application/json" \
     --data '{"type":"TXT","name":"'"$CREATE_DOMAIN"'","content":"'"$CERTBOT_VALIDATION"'","ttl":120}' \
             | python -c "import sys,json;print(json.load(sys.stdin)['result']['id'])")
# Save info for cleanup
if [ ! -d /tmp/CERTBOT_$CERTBOT_DOMAIN ];then
        mkdir -m 0700 /tmp/CERTBOT_$CERTBOT_DOMAIN
fi
echo $ZONE_ID > /tmp/CERTBOT_$CERTBOT_DOMAIN/ZONE_ID
echo $RECORD_ID > /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID

# Sleep to make sure the change has time to propagate over to DNS
sleep 25
#!/bin/bash

# 在 https://dash.cloudflare.com/profile 获取API_KEY
API_KEY=
EMAIL=

if [ -f /tmp/CERTBOT_$CERTBOT_DOMAIN/ZONE_ID ]; then
        ZONE_ID=$(cat /tmp/CERTBOT_$CERTBOT_DOMAIN/ZONE_ID)
        rm -f /tmp/CERTBOT_$CERTBOT_DOMAIN/ZONE_ID
fi

if [ -f /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID ]; then
        RECORD_ID=$(cat /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID)
        rm -f /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID
fi

# Remove the challenge TXT record from the zone
if [ -n "${ZONE_ID}" ]; then
    if [ -n "${RECORD_ID}" ]; then
        curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \
                -H "X-Auth-Email: $EMAIL" \
                -H "X-Auth-Key: $API_KEY" \
                -H "Content-Type: application/json"
    fi
fi

测试了一下命令,终于不冒红字了,加进crontab,收工。

/root/certbot-auto renew --manual --manual-auth-hook /etc/letsencrypt/authenticator.sh --manual-cleanup-hook /etc/letsencrypt/cleanup.sh --renew-hook "/etc/init.d/nginx reload" --dry-run
0 0 */15 * * /root/certbot-auto renew --manual --manual-auth-hook /etc/letsencrypt/authenticator.sh --manual-cleanup-hook /etc/letsencrypt/cleanup.sh --renew-hook "/etc/init.d/nginx reload"

暂无评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注