# 使用 Duck DNS 获取 Let’s Encrypt 证书

# 注册 Duck DNS

https://www.duckdns.org/

# 安装 certbot

# nginx 服务器 (Ubuntu)

# 安装 certbot

sudo apt install certbot
sudo apt install python3-certbot-nginx

# 创建申请

sudo certbot --manual --preferred-challenges dns certonly

后会有类似以下提示:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:
_acme-challenge.test.duckdns.org.
with the following value:
sz8QCaKoQBBO5pYqTIUIVr-twoQYaa5yYiWHfcuDDTo
    
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

# 更改 TXT 记录

# curl https://www.duckdns.org/update?domains={YOURVALUE}&token={YOURVALUE}&txt={YOURVALUE}
# 也可以浏览器访问,回显 "OK"
curl https://www.duckdns.org/update?domains=test.duckdns.org&token=00000000-0000-0000-0000-00000000000f&txt=sz8QCaKoQBBO5pYqTIUIVr-twoQYaa5yYiWHfcuDDTo

# 继续申请

Enter

# 成功提示

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/test.duckdns.org/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/test.duckdns.org/privkey.pem
This certificate expires on 2023-08-18.
These files will be updated when the certificate renews.
NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

证书: /etc/letsencrypt/live/test.duckdns.org/fullchain.pem
私钥: /etc/letsencrypt/live/test.duckdns.org/privkey.pem

# 创建自动续签任务

保存 certbot-auth-duckdns.sh

#!/bin/bash
#
# Create: certbot certonly --manual --preferred-challenges dns-01 --email mail@domain.com -d laravel.run -d *.laravel.run --server https://acme-v02.api.letsencrypt.org/directory --manual-auth-hook /path/to/certbot-auth-duckdns.sh
# Renew:  certbot renew --manual-auth-hook /path/to/certbot-auth-duckdns.sh
#
# https://github.com/al-one/certbot-auth-dnspod/
API_TOKEN=""
if [ -z "$API_TOKEN" ]; then
    [ -f $HOME/.duckdns_token_$CERTBOT_DOMAIN ] && API_TOKEN=$(cat $HOME/.duckdns_token_$CERTBOT_DOMAIN)
fi
if [ -z "$API_TOKEN" ]; then
    [ -f /etc/duckdns_token_$CERTBOT_DOMAIN ] && API_TOKEN=$(cat /etc/duckdns_token_$CERTBOT_DOMAIN)
fi
if [ -z "$API_TOKEN" ]; then
    [ -f $HOME/.duckdns_token ] && API_TOKEN=$(cat $HOME/.duckdns_token)
fi
if [ -z "$API_TOKEN" ]; then
    [ -f /etc/duckdns_token ] && API_TOKEN=$(cat /etc/duckdns_token)
fi
if [ -z "$API_TOKEN" ]; then
    API_TOKEN="$DUCKDNS_TOKEN"
fi
echo "\
DOMAIN: $CERTBOT_DOMAIN
VALIDATION:     $CERTBOT_VALIDATION"
# CERTBOT_DOMAIN: test.duckdns.org
# VALIDATION:     ********
# curl https://www.duckdns.org/update?domains=test.duckdns.org&token=00000000-0000-0000-0000-00000000000f&txt=sz8QCaKoQB
if [ "$1" = "clean" ]; then
    APIRET=$(curl -s "https://www.duckdns.org/update?domains=$CERTBOT_DOMAIN&token=$API_TOKEN&txt=")
    echo "Remove Record: $CERTBOT_DOMAIN - $APIRET"
else
    APIRET=$(curl -s "https://www.duckdns.org/update?domains=$CERTBOT_DOMAIN&token=$API_TOKEN&txt=$CERTBOT_VALIDATION")
    echo "Update Record: $CERTBOT_DOMAIN - $APIRET"
    # Sleep to make sure the change has time to propagate over to DNS
    sleep 30
fi
sudo crontab -e

保持在线状态以免证书被吊销。在证书到期或续订之前不会执行任何操作。

0 */12 * * * export DUCKDNS_TOKEN=00000000-0000-0000-0000-00000000000f && python3 -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew --manual-auth-hook /path/to/certbot-auth-duckdns.sh
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/test.duckdns.org.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewing an existing certificate for test.duckdns.org
Hook '--manual-auth-hook' for test.duckdns.org ran with output:
 CERTBOT_DOMAIN: test.duckdns.org
 VALIDATION:     sz8QCaKoQBBO5pYqTIUIVr-twoQYaa5yYiWHfcuDDTo
 Update Record:  test.duckdns.org - OK
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded: 
  /etc/letsencrypt/live/test.duckdns.org/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

# 参考

Letsencrypt 通过 DNS 的 TXT 记录来验证域名有效性
Certbot DNS Authenticator For DNSPod