目录

「CloudFlare」拔剑四顾心茫然

CloudFlare 功能配置指南。

Tokens / API

DNS

DDNS

By Tokens
# tool downloaded from: https://github.com/NewFuture/DDNS
# wget -N https://github.com/NewFuture/DDNS/releases/download/v2.13.3/ddns -P <path/to/save>
# curl https://github.com/NewFuture/DDNS/releases/download/v2.13.3/ddns -#SLo ddns && chmod +x ddns
pip install ddns
ddns -c aptiv.linux.config.json
{
  "$schema": "https://ddns.newfuture.cc/schema/v2.8.json",
  "debug": false,
  "dns": "cloudflare",
  "id": "",
  "index4": "url:http://ipv4.icanhazip.com",
  "index6": "default",
  "ipv4": [
    "aptiv.linux.yirami.xyz"
  ],
  "ipv6": [],
  "proxy": null,
  "token": "6R0bpfO8vwIu02kdHYHwXOzWsMmB0x2Vf-v3IfEA",
  "ttl": null
}
By API
# curl https://gist.githubusercontent.com/benkulbertis/fff10759c2391b6618dd/raw > /usr/local/bin/cf-ddns.sh && chmod +x /usr/local/bin/cf-ddns.sh

#!/bin/bash

# CHANGE THESE
auth_email="service@yirami.xyz"
auth_key="9???f" # found in cloudflare account settings: https://dash.cloudflare.com/profile/api-tokens
zone_name="yirami.xyz"
record_name="aptiv.linux.yirami.xyz"

# MAYBE CHANGE THESE
ip=$(curl -s http://ipv4.icanhazip.com)
ip_file="ip.txt"
id_file="cloudflare.ids"
log_file="cloudflare.log"

# LOGGER
log() {
    if [ "$1" ]; then
        echo -e "[$(date)] - $1" >> $log_file
    fi
}

# SCRIPT START
log "Check Initiated"

if [ -f $ip_file ]; then
    old_ip=$(cat $ip_file)
    if [ $ip == $old_ip ]; then
        echo "IP has not changed."
        exit 0
    fi
fi

if [ -f $id_file ] && [ $(wc -l $id_file | cut -d " " -f 1) == 2 ]; then
    zone_identifier=$(head -1 $id_file)
    record_identifier=$(tail -1 $id_file)
else
    zone_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$zone_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
    record_identifier=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json"  | grep -Po '(?<="id":")[^"]*')
    echo "$zone_identifier" > $id_file
    echo "$record_identifier" >> $id_file
fi

update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"name\":\"$record_name\",\"content\":\"$ip\"}")

if [[ $update == *"\"success\":false"* ]]; then
    message="API UPDATE FAILED. DUMPING RESULTS:\n$update"
    log "$message"
    echo -e "$message"
    exit 1 
else
    message="IP changed to: $ip"
    echo "$ip" > $ip_file
    log "$message"
    echo "$message"
fi

CA

Certificate Auto-enrollment

By Certbot + CloudFlare Token + Let’s Encrypt
  • generate

Debian 11/12 PASSED

sudo apt update
sudo apt install -y certbot

# Debian 11
pip install --upgrade certbot-dns-cloudflare
# or Debian 12
sudo apt install -y python3-certbot-dns-cloudflare

# create token from CloudFlare: https://dash.cloudflare.com/profile/api-tokens
# tokens = "pAfWMQ???l"

mkdir -p ~/yirami/certbot
cat > ~/yirami/certbot/cloudflare.ini << EOF
dns_cloudflare_api_token = xxxxxxxxxxxxxxxxxxxxxxx
EOF

# 保证仅所有者有读写权限
chmod 600 /root/yirami/certbot/cloudflare.ini

#
certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials=/root/yirami/certbot/cloudflare.ini \
  --dns-cloudflare-propagation-seconds=60 \
  -d yirami.xyz \
  -d x.yirami.xyz \
  -d loc.sjus.yirami.xyz \
  -d loc.laus.yirami.xyz \
  -d aptiv.linux.yirami.xyz \
  -d www.yirami.xyz

# confugure is saved at: /etc/letsencrypt/renewal/yirami.xyz.conf
# certificate is saved at: /etc/letsencrypt/live/yirami.xyz
  • used by nginx
vim /usr/local/nginx/conf/vhost/yirami.xyz.conf
# update: ssl_certificate /etc/letsencrypt/live/yirami.xyz/fullchain.pem;
# update: ssl_certificate_key /etc/letsencrypt/live/yirami.xyz/privkey.pem;

# test and reload
nginx -t
# systemctl reload nginx
lnmp reload nginx
  • renew & auto-renew
certbot renew

# https://eff-certbot.readthedocs.io/en/latest/using.html#setting-up-automated-renewal
# 1. check if task has been created
systemctl list-timers | grep certbot
# 2. or add the task directly
SLEEPTIME=$(awk 'BEGIN{srand(); print int(rand()*(3600+1))}'); echo "0 0,12 * * * root sleep $SLEEPTIME && certbot renew -q" | tee -a /etc/crontab > /dev/null

# pre & post tasks
sh -c 'printf "#!/bin/sh\nlnmp stop nginx\n" > /etc/letsencrypt/renewal-hooks/pre/nginx.sh'  # 尝试前执行(无论是否成功)
sh -c 'cat <<EOF > /etc/letsencrypt/renewal-hooks/deploy/nginx.sh
#!/bin/bash
echo "[\$(date)] Renewed certificate, reloading LNMP..."
/usr/bin/lnmp reload
EOF'  # 成功续期后执行
sh -c 'printf "#!/bin/sh\nlnmp reload nginx\n" > /etc/letsencrypt/renewal-hooks/post/nginx.sh'  # 续期结束后执行(无论是否成功)
chmod 755 /etc/letsencrypt/renewal-hooks/pre/nginx.sh
chmod 755 /etc/letsencrypt/renewal-hooks/deploy/nginx.sh
chmod 755 /etc/letsencrypt/renewal-hooks/post/nginx.sh

# test
certbot renew --dry-run  # 似乎需要实际有证书需要续期

参考

  1. 利用CloudFlare设置Dynamic DNS(DDNS)获取动态IP

  2. 使用CloudFlare做DDNS解析(Global API)

  3. 使用CloudFlare做DDNS解析(API Token)

  4. 通过 Certbot+Cloudflare 自动申请证书