Hot For Coding

certbot自动续签与更新Dnspod记录脚本

full

Let's Encrypt为了推广HTTPS的普及,提供了免费证书,麻烦的是每三个月就到期,需要重新续签一下。重新续签有两种途径

  • 自动续签
  • 手动续签

自动续签与国际通用的DNS提供商有较好的合作支持,但对于国内比如Dnspod没有在它的自动续签支持里,不过它提供hook,你可以写任意shell脚本完成TXT记录即可实现自动续签。

Dndpod从新版开始token直接采用id,token组合而成,这里需要注意一下,脚本如下

renew.sh

#!/bin/bash
#
# Description:
#   This program will auto obtain a Let's Encrypt certificate for qttc.net with Dnspod
#
# Author: Nicholas Lee <lizhongit@gmail.com>
#
#
# Reference:
#   Certbot https://certbot.eff.org/docs/
# 
# 2020, April 29    First release
#

DNSPOD_TOKEN=[YOUR DNSPOD TOKEN]
DNSPOD_ID=[YOUR DNSPOD ID]

USER_AGENT='Qttc Renew Client/1.0.0(lizhongit@gmail.com)'
DOMAIN=qttc.net


echo "\
CERTBOT_DOMAIN: $CERTBOT_DOMAIN
DOMAIN:         $DOMAIN
VALIDATION:     $CERTBOT_VALIDATION"

if [ -f /tmp/CERTBOT_$CERTBOT_DOMAIN/VALIDATION ]; then
  VALIDATION_PRE=$(cat /tmp/CERTBOT_$CERTBOT_DOMAIN/VALIDATION)
  if [ "$CERTBOT_VALIDATION" = "$VALIDATION_PRE" ]; then  
    echo "Same Validation: $CERTBOT_VALIDATION"
    exit
  fi
fi


# Getting record id of named _acme-challenge

RECORD=$(curl -s -X POST "https://dnsapi.cn/Record.List" \
        -H "User-Agent: $USER_AGENT" \
        -d "login_token=$DNSPOD_ID,$DNSPOD_TOKEN&format=json&domain=$DOMAIN&record_type=TXT&keyword=_acme-challenge&lang=en" \
  | python -c "import sys,json;ret=json.load(sys.stdin);print(ret.get('records',[{}])[0].get('id',ret.get('status',{}).get('message','error')))")

echo "RECORD: $RECORD"

sleep 3

# Updating record with validation value

if [ -n "$RECORD" ]; then
  RET=echo $(curl -s -X POST "https://dnsapi.cn/Record.Modify" \
        -H "User-Agent: $USER_AGENT" \
        -d "login_token=$DNSPOD_ID,$DNSPOD_TOKEN&format=json&domain=$DOMAIN&record_id=$RECORD&sub_domain=_acme-challenge&record_type=TXT&record_line_id=0&value=$CERTBOT_VALIDATION&lang=en" \
  | python -c "import sys,json;sys.stdin = UTF8Reader(sys.stdin);ret=json.load(sys.stdin);print(ret.get('status',{}).get('message', ''))")

else
  RET=$(curl -s -X POST "https://dnsapi.cn/Record.Create" \
        -H "User-Agent: $USER_AGENT" \
        -d "login_token=$DNSPOD_ID,$DNSPOD_TOKEN&format=json&domain=$DOMAIN&sub_domain=_acme-challenge&record_type=TXT&value=$CERTBOT_VALIDATION&lang=en" \
  | python -c "import sys,json;ret=json.load(sys.stdin);print(ret.get('status',{}).get('message', ''))")
fi

echo "Dnspod result: $RET"

# Save info for cleanup
if [ ! -d /tmp/CERTBOT_$CERTBOT_DOMAIN ]; then
  mkdir -m 0700 /tmp/CERTBOT_$CERTBOT_DOMAIN
fi
echo $DOMAIN > /tmp/CERTBOT_$CERTBOT_DOMAIN/DOMAIN
echo $CERTBOT_VALIDATION > /tmp/CERTBOT_$CERTBOT_DOMAIN/VALIDATION 

# Sleep to make sure the change has time to propagate over to DNS
while [ -n "$TXT_RECORD" ]
do
  TXT_RECORD=$(/usr/bin/dig _acme-challenge.qttc.net txt | grep "$CERTBOT_VALIDATION")
  sleep 10
done

sleep 10

以上脚本有几个环境变量需要说明一下,当你执行certbot-auto hook此脚本时,会自动预置几个变量,其中最最重要的变量是$CERTBOT_VALIDATION,你需要用它去改写dnspod的TXT值。

为了防止默认dnspod返回中文字符导致Python包字符集错误,我这里图省事就在所有的dnspod请求加一个参数lang=en要求返回英文。

最后只需要使用certbot-auto配合此脚本即可实现自动续签证书

#!/bin/bash
certbot-auto certonly --server https://acme-v02.api.letsencrypt.org/directory --preferred-challenges dns-01 -d *.qttc.net -d qttc.net --manual-auth-hook ./renew.sh --manual --non-interactive --agree-tos --manual-public-ip-logging-ok

如果提示没有dig命令,安装一下dnsutils就好

apt install -y dnsutils

最后,我们可以放到计划任务让它每80天执行一次,为了什么是80天呢?因为90天就过期,太早了会申请失败,所以比较合适的时间就是80天左右。

Crontab里要描述每80天执行一次还是比较麻烦的,所以采用了比较流行的Systemd来干这个事

/etc/systemd/system/qttc-ssl-auto.service

[Unit]
Description=Auto renew SSL for qttc.net

[Service]
Type=simple
ExecStart=/root/qttc_cron.sh

[Install]
WantedBy=multi-user.target

/etc/systemd/system/qttc-ssl-auto.timer

[Unit]
Description=Run it on each 80 days

[Timer]
OnUnitActiveSec=80d

[Install]
WantedBy=multi-user.target

System开启一下

systemctl enable qttc-ssl-auto.service
systemctl enable qttc-ssl-auto.timer

一切搞定,以后每80天会自动续签一次SSL证书

TITLE: certbot自动续签与更新Dnspod记录脚本

LINK: https://www.qttc.net/519_certbot_auto_with_dnspod.html

NOTE: 转载内容请注明出处