• 技术 | Technology
  • 零基础学会如何自动更新托管在cloudflare上的域名解析记录 【支持A、AAAA、CNAME、TXT】

最近有佬友经常在问:自己的环境有公网但不固定,如何能够将当前的公网IP自动提交到cloudflare进行更新。
针对这个问题咱们就出一个简单的教程,并且花了10分钟手搓了一个shell脚本(完全遵循POSIX规范,理论上没有兼容性问题)。

第一部分:在cloudflare上申请API管理域名的token

1.打开cloudflare面板 https://dash.cloudflare.com/
2.点击右上角个人头像,找到 Profile 并点击
3.点击最左侧 API Tokens,找到 CreateToken 并点击
4.点击文字 Edit zone DNS 右边的 Use template 按钮
5.将 Zone Resources 区域里的第二个下拉框更改为 All zones
6.点击页面最下方 Continue to summary
7.点击 Create Token,稍等片刻就会出现token字符串
最后在成功页面找到token字符串并复制下来。因为这个token仅会出现一次,所以一定要把token保存好。

第二部分:会用到的几个API接口

headers是固定的 "Authorization: Bearer token字符串" "Content-Type:application/json“
查询根域名的zoneid
    https://api.cloudflare.com/client/v4/zones?name=根域名
查询子域名的解析记录
    https://api.cloudflare.com/client/v4/zones/根域名zoneid/dns_records?name=子域名&type=解析类型(可为空)
新增解析记录
    https://api.cloudflare.com/client/v4/zones/根域名zoneid/dns_records 新增解析记录
    POST {"type":"记录类型","name":"子域名称","content":"解析记录值","ttl":1,"proxied":是否开启小黄云(true/false)}
修改解析记录
    https://api.cloudflare.com/client/v4/zones/根域名zoneid/dns_records/子域ID 修改解析记录
    PUT {"id":"根域名zoneid","type":"记录类型","name":"子域名称","content":"解析记录值","ttl":1,"proxied":是否开启小黄云(true/false)}

第三部分:手搓的shell成品 cfddns.sh

#!/bin/bash
get_wan_ip(){
    ip4=$(curl -s -m 5 -4 http://api64.ipify.org/)
    echo $ip4 | grep -F "." >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo $ip4
    else
        echo ""
    fi
}
get_wan_ip6(){
    ip6=$(curl -s -m 5 -6 http://api64.ipify.org/)
    echo $ip6 | grep -F ":" >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo $ip6
    else
        echo ""
    fi
}
dns_isupdated(){
    dns_line=$(nslookup $domain2 lia.ns.cloudflare.com 2>/dev/null)
    for line in $dns_line
    do
        if [ "$line" = "$checkip" ]; then return 1; fi
    done
    return 0
}
func=$1 ; token=$2 ; domaininfo=$3 ; ip=$4 ; ipv6=$5
echo $domaininfo | grep -F "#" >/dev/null 2>&1
if [ $? -eq 0 ]; then
    domain=$(echo $domaininfo | awk -F '#' '{print $NF}')
    domain2=$(echo $domaininfo | sed -e 's/#/./gi')
else
    domain=${domaininfo#*.}
    domain2=$domaininfo
fi
if [ "$func" = "" ]; then echo "wrong parameter (v4v6 token domain2 ip ipv6)" ; exit 1 ; fi
if [ "$ip" = "auto" ]; then ip=""; fi
if [ "$ipv6" = "auto" ]; then ipv6=""; fi
domain2=$(echo $domain2 | sed 's/@.//g')
types=""
proxied=false ; echo $func | grep -F "#" >/dev/null 2>&1
if [ $? -eq 0 ]; then proxied=true; fi
echo $func | grep -F "v4" >/dev/null 2>&1
if [ $? -eq 0 ]; then
    htype=1
    if [ "$ip" = "" ]; then ip=$(get_wan_ip); fi
    if [ "$ip" != "" ]; then
        if [ "$proxied" = "true" ];then
            types=$types"A "
        else
            checkip=$ip
            if dns_isupdated ; then
                types=$types"A "
            else
                echo "$domain2 A Record is ready"
            fi
        fi
    fi
fi
echo $func | grep -F "v6" >/dev/null 2>&1
if [ $? -eq 0 ]; then
    htype=1
    if [ "$ipv6" = "" ]; then ipv6=$(get_wan_ip6); fi
    if [ "$ipv6" != "" ]; then
        if [ "$proxied" = "true" ];then
            types=$types"AAAA "
        else
            checkip=$ipv6
            if dns_isupdated ; then
                types=$types"AAAA "
            else
                echo "$domain2 AAAA Record is ready"
            fi
        fi
    fi
fi
if [ "$types" = "" ] && [ "$htype" = "1" ]; then exit 0; fi
if [ "$types" = "" ]; then types=$(echo $func | sed -e 's/#//gi'); fi
html=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$domain" -H "Authorization: Bearer $token" -H "Content-Type:application/json")
zoneid=$(echo $html | sed -e 's/,"status":"/#\n/g' | grep -F "\"$domain\"" | awk -F '"id":"' 'NR==1{print $NF}' | cut -f 1 -d '"')
if [ "$zoneid" = "" ]; then echo "no zoneid" ; exit 2 ; fi
for type in $types
do
    newip=$ip;newinfo=""
    if [ "$type" = "AAAA" ]; then newip=$ipv6; fi
    if [ "$type" = "TXT" ]; then newip="\\\"$newip\\\""; fi
    html=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?name=$domain2&type=$type" -H "Authorization: Bearer $token" -H "Content-Type:application/json")
    echo $html | grep -F "\"success\":true" | grep -v "grep" >/dev/null 2>&1
    if [ $? -ne 0 ]; then echo "no data" ; continue ; fi
    domain2id=$(echo $html | awk -F '"id":"' '{print $2}' | cut -f 1 -d '"')
    if [ "$domain2id" = "" ]; then
        html=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records" -H "Authorization: Bearer $token" -H "Content-Type:application/json" --data "{\"type\":\"$type\",\"name\":\"$domain2\",\"content\":\"$newip\",\"ttl\":1,\"proxied\":$proxied}")
    else
        ready=false
        echo $html | grep -F "\"content\":\"$newip\"" >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            echo $html | grep -F "\"proxied\":$proxied" >/dev/null 2>&1
            if [ $? -eq 0 ]; then
                ready=true
            fi
        fi
        if [ "$ready" = "true" ]; then
            html='"success":true' ; newinfo="(ready)"
        else
            html=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$domain2id" -H "Authorization: Bearer $token" -H "Content-Type:application/json" --data "{\"id\":\"$zoneid\",\"type\":\"$type\",\"name\":\"$domain2\",\"content\":\"$newip\",\"ttl\":1,\"proxied\":$proxied}")
        fi
    fi
    echo $html | grep -F "\"success\":true" | grep -v "grep" >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        echo "$domain2 $type Record $newip update fail"
        echo $html
    else
        echo "$domain2 $type Record $newip update$newinfo success"
    fi
done

第四部分:使用shell脚本

如果想要解析根域名那么将 子域名 替换成 @
如果想要解析成固定IP那么将 auto 替换成 你的IP地址

#仅解析ipv4
sh cfddns.sh v4 token字符串 v4name#mydomain.com auto
#仅解析ipv6
sh cfddns.sh v6 token字符串 v6name#mydomain.com auto auto
#同时解析ipv4和ipv6
sh cfddns.sh v4v6 token字符串 v46name#mydomain.com auto auto
#解析CNAME
sh cfddns.sh CNAME token字符串 cname#mydomain.com www.google.com

如果以上解析记录想要开启小黄云,则修改成 v4#、v6#、v4v6#、CNAME#

#解析TXT记录
sh cfddns.sh TXT token字符串 ctxt#mydomain.com "Welcome to my txt record"

寄语:
曾经有佬友问我经常发教程为什么不设置权限(比如回复才可以阅读什么的),不仅可以防止白嫖还能增加回复量。

其实写这些教程的初衷,最重要的还是分享和交流,和佬友们共同进步。
关于回帖这个问题,我相信如果写的好、写的对佬友有用,佬友必定会所回复和反馈的。

我坚信尊重他人也是尊重自己的一种表现。

Good luck to all

打赏

    感谢大佬来传道,篇篇都是精品 !!!

    谢谢大佬,你不能说的是我吧,我正在为DDNS犯愁呢。

    及时雨啊,及时雨啊,今天在网上找了很多,几乎都要装一堆东西,而且要传好几个参数,大佬的只要token就行而且还是开源的。牛X

    真心佩服,请收下我的敬意。

    试了下我的环境,木有问题。

    感谢大佬分享,又是好教程,大佬发的每次都看,基本都能看明白,谢谢

    受教了大佬,刚试了一下,而且还支持多级域名解析 比如a.b.c.d.mydomain.com,开放型的教程

    • dani

      气氛组
    • #6

    江湖大佬。

    大佬受教了,收藏huaji03

    学习一下

      emo组
    • #9

    真细致啊,收藏了

    谢了,收藏用

    • x

      YEAR
    • #11

    感谢分享 xhj06

    感谢大佬分享,收藏下来等开了公网地址一步一步试试ac08

    感谢大佬分享

    感谢大佬来传道,篇篇都是精品 !!!

    太好用了,一次成功。
    大佬的教程太细致了,代码可读性也强ac52

    谢谢,真心不错,很详细,一遍过

    太强了大佬,学习到了

    1 个月 后

    感谢江湖大佬,收下了