├── README.md
└── cloudflare-ddns.sh
/README.md:
--------------------------------------------------------------------------------
1 | # 功能
2 | 自动调度Cloudflare云端分钟更新一次
3 | 优选IP速度大于100Mbps
4 | 全天99%在线
5 |
6 | ## 食用方式
7 | ### 准备工作
8 | 一台VPS(国内、国外均可),域名,cloudflare账号
9 | ### 步骤
10 | 1. 登录cloudflare账号,获取Global API Key
11 | 
12 |
13 | 
14 |
15 | 2. 登录VPS,复制下方命令执行
16 | ```shell
17 | wget -O cloudflare-ddns.sh https://raw.githubusercontent.com/jinqians/cloudflare-ddns/main/cloudflare-ddns.sh && chmod +x cloudflare-ddns.sh && ./cloudflare-ddns.sh
18 | ```
19 | 输入自己的对应信息
20 | 
21 |
22 | 3. 执行完成后按照提示,输入下方命令执行
23 | ```shell
24 | ./cloudflare.sh
25 | ```
26 | 到此,优选IP已绑定到自己的域名
27 |
--------------------------------------------------------------------------------
/cloudflare-ddns.sh:
--------------------------------------------------------------------------------
1 | #Telegram:@jinqians_chat
2 | #!/usr/bin/env bash
3 | set -o errexit
4 | set -o nounset
5 | set -o pipefail
6 |
7 | # 欢迎信息
8 | echo "欢迎使用Cloudflare 自动优选IP 群组:@jinqians_chat"
9 | read -p "点击任意键继续.."
10 |
11 | # 用户输入
12 | read -p "请输入您的Cloudflare Global API Key(https://dash.cloudflare.com/profile/api-tokens): " CFKEY
13 | read -p "请输入您的Cloudflare 登录邮箱: " CFUSER
14 | read -p "请输入您的Cloudflare DNS域名(一级域名): " CFZONE_NAME
15 | read -p "请输入您的Cloudflare DDNS域名(二级域名): " CFRECORD_NAME
16 |
17 | # 提醒信息
18 | echo "请注意确保二级域名已随意添加一个解析并未开启代理"
19 | read -p "按任意键回车继续.."
20 |
21 | # 生成新的DDNS脚本文件
22 | cat < cloudflare.sh
23 | #!/usr/bin/env bash
24 | set -o errexit
25 | set -o nounset
26 | set -o pipefail
27 |
28 | # Cloudflare API credentials
29 | CFKEY="$CFKEY"
30 | CFUSER="$CFUSER"
31 | CFZONE_NAME="$CFZONE_NAME"
32 | CFRECORD_NAME="$CFRECORD_NAME"
33 |
34 | # 记录类型,A(IPv4)|AAAA(IPv6),默认为IPv4
35 | CFRECORD_TYPE=A
36 |
37 | # Cloudflare记录的TTL,介于120和86400秒之间
38 | CFTTL=120
39 |
40 | # 无视本地文件,无论如何都更新IP
41 | FORCE=false
42 |
43 | # 获取WAN IP的网站
44 | WANIPSITE="https://ipdb.api.030101.xyz/?type=bestproxy&country=false"
45 |
46 | # 获取参数
47 | while getopts k:u:h:z:t:f: opts; do
48 | case \${opts} in
49 | k) CFKEY=\${OPTARG} ;;
50 | u) CFUSER=\${OPTARG} ;;
51 | h) CFRECORD_NAME=\${OPTARG} ;;
52 | z) CFZONE_NAME=\${OPTARG} ;;
53 | t) CFRECORD_TYPE=\${OPTARG} ;;
54 | f) FORCE=\${OPTARG} ;;
55 | esac
56 | done
57 |
58 | # 如果必需的设置缺失,则退出
59 | if [ "\$CFKEY" = "" ]; then
60 | echo "缺少API密钥,请在 https://www.cloudflare.com/a/account/my-account 获取"
61 | echo "并保存在 \${0} 或使用 -k 参数"
62 | exit 2
63 | fi
64 | if [ "\$CFUSER" = "" ]; then
65 | echo "缺少用户名,可能是您的电子邮件地址"
66 | echo "并保存在 \${0} 或使用 -u 参数"
67 | exit 2
68 | fi
69 | if [ "\$CFRECORD_NAME" = "" ]; then
70 | echo "缺少主机名,您想要更新哪个主机?"
71 | echo "保存在 \${0} 或使用 -h 参数"
72 | exit 2
73 | fi
74 |
75 | # 如果主机名不是完整域名
76 | if [ "\$CFRECORD_NAME" != "\$CFZONE_NAME" ] && ! [ -z "\${CFRECORD_NAME##*\$CFZONE_NAME}" ]; then
77 | CFRECORD_NAME="\$CFRECORD_NAME.\$CFZONE_NAME"
78 | echo " => 主机名不是完整域名,假设为 \$CFRECORD_NAME"
79 | fi
80 |
81 | # 检查IP地址是否有效的函数
82 | is_valid_ip() {
83 | local ip=\$1
84 | if [[ \$ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\$ ]]; then
85 | return 0
86 | else
87 | return 1
88 | fi
89 | }
90 |
91 | # 从主要IP源获取当前和旧的WAN IP
92 | WAN_IP=$(curl -s "$WANIPSITE" | head -n 1 | awk -F '#' '{print $1}')
93 |
94 | # 如果WAN_IP无效,尝试备用IP源
95 | if ! is_valid_ip "\$WAN_IP"; then
96 | WAN_IP=$(curl -s "https://ipdb.api.030101.xyz/?type=bestcf&country=false" | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" | head -n 1)
97 | if ! is_valid_ip "\$WAN_IP"; then
98 | echo "无法获取有效的IPv4地址"
99 | exit 1
100 | fi
101 | fi
102 |
103 | echo "IPv4 \$WAN_IP 已获取"
104 |
105 | WAN_IP_FILE=\$HOME/.cf-wan_ip_\$CFRECORD_NAME.txt
106 | if [ -f \$WAN_IP_FILE ]; then
107 | OLD_WAN_IP=\$(cat \$WAN_IP_FILE)
108 | else
109 | echo "没有找到对应的输出文件 @jinqians_chat"
110 | OLD_WAN_IP=""
111 | fi
112 |
113 | # 如果WAN IP没有变化且没有强制更新标志,则退出
114 | if [ "\$WAN_IP" = "\$OLD_WAN_IP" ] && [ "\$FORCE" = false ]; then
115 | echo "云端没有最新的优选IP @@jinqians_chat"
116 | exit 0
117 | fi
118 |
119 | # 获取区域标识符和记录标识符
120 | ID_FILE=\$HOME/.cf-id_\$CFRECORD_NAME.txt
121 | if [ -f \$ID_FILE ] && [ \$(wc -l \$ID_FILE | cut -d " " -f 1) == 4 ] \
122 | && [ "\$(sed -n '3,1p' "\$ID_FILE")" == "\$CFZONE_NAME" ] \
123 | && [ "\$(sed -n '4,1p' "\$ID_FILE")" == "\$CFRECORD_NAME" ]; then
124 | CFZONE_ID=\$(sed -n '1,1p' "\$ID_FILE")
125 | CFRECORD_ID=\$(sed -n '2,1p' "\$ID_FILE")
126 | else
127 | echo "正在更新区域标识符和记录标识符"
128 | CFZONE_ID=\$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=\$CFZONE_NAME" -H "X-Auth-Email: \$CFUSER" -H "X-Auth-Key: \$CFKEY" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
129 | CFRECORD_ID=\$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/\$CFZONE_ID/dns_records?name=\$CFRECORD_NAME" -H "X-Auth-Email: \$CFUSER" -H "X-Auth-Key: \$CFKEY" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )
130 | echo "\$CFZONE_ID" > \$ID_FILE
131 | echo "\$CFRECORD_ID" >> \$ID_FILE
132 | echo "\$CFZONE_NAME" >> \$ID_FILE
133 | echo "\$CFRECORD_NAME" >> \$ID_FILE
134 | fi
135 |
136 | # 更新Cloudflare DNS记录
137 | if is_valid_ip "\$WAN_IP"; then
138 | RESPONSE=\$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/\$CFZONE_ID/dns_records/\$CFRECORD_ID" \
139 | -H "X-Auth-Email: \$CFUSER" \
140 | -H "X-Auth-Key: \$CFKEY" \
141 | -H "Content-Type: application/json" \
142 | --data "{\"id\":\"\$CFZONE_ID\",\"type\":\"\$CFRECORD_TYPE\",\"name\":\"\$CFRECORD_NAME\",\"content\":\"\$WAN_IP\", \"ttl\":\$CFTTL}")
143 |
144 | if [ "\$RESPONSE" != "\${RESPONSE%success*}" ] && [ "\$(echo \$RESPONSE | grep "\"success\":true")" != "" ]; then
145 | echo "已同步到Cloudflare!"
146 | echo \$WAN_IP > \$WAN_IP_FILE
147 | else
148 | echo '出现错误 :('
149 | echo "响应: \$RESPONSE"
150 | exit 1
151 | fi
152 | else
153 | echo "IP地址无效,无法更新DNS记录"
154 | exit 1
155 | fi
156 | EOF
157 |
158 | # 赋予新脚本执行权限
159 | chmod +x cloudflare.sh
160 |
161 | # 设置计划任务
162 | (crontab -l 2>/dev/null; echo "* * * * * $(pwd)/cloudflare.sh") | crontab -
163 |
164 | # 完成提示
165 | echo "成功生成对应的配置文件,请执行 ./cloudflare.sh"
166 |
167 | # 提示用户计划任务已设置
168 | echo "计划任务已设置,脚本将每分钟运行一次。"
169 |
--------------------------------------------------------------------------------