导读:本期聚焦于Amelis创作的《如何编写Cloudflare DDNS自动更新脚本实现动态域名解析?》,敬请观看详情。家庭宽带或服务器使用动态IP时,直接在路由器上配置DDNS经常遇到解析记录不生效、TTL过长导致访问失败的问题。其实通过Cloudflare API编写一个专属的DDNS自动更新脚本,不仅能精准控制记录刷新频率,还能利用Cloudflare全球网络加速访问。本文将详细讲解如何获取Cloudflare API Token、查询本机公网IP地址、调用API更新A记录,以及通过定时任务实现全自动运行。同时会分析脚本容错机制、日志记录和并发冲突处理等进阶技巧,帮助你搭建一个稳定可靠的动态域名解析服务。

动态IP环境下要保持域名始终指向正确的服务器地址,Cloudflare提供的API让这一切变得简单可控。相比于依赖路由器自带的DDNS客户端,自己编写更新脚本可以完全掌控刷新逻辑、错误处理和日志记录,同时还能利用Cloudflare的CDN网络隐藏真实IP。整个方案的核心思路是:定时检测本机公网IP,发现变化后调用Cloudflare API更新对应的DNS记录。

如何编写Cloudflare DDNS自动更新脚本实现动态域名解析?

一、准备工作:获取API Token与必要参数

要让脚本能够操作你的DNS记录,首先需要在Cloudflare控制台创建一个API Token。登录Cloudflare仪表板后,点击右上角头像图标,进入My Profile页面,找到API Tokens选项卡。点击Create Token按钮,选择Create Custom Token,这里不需要使用Global API Key,因为Global API Key拥有账户的全部权限,一旦泄露风险极大。

在权限设置区域,选择Zone类型的DNS资源,授予Edit编辑权限。Zone Resources区域选择Include Specific zone,然后从下拉菜单中挑选你要管理的域名。这样创建出来的Token只能操作指定域名的DNS记录,即使脚本文件被泄露,攻击者也无法触及其他资源。创建完成后系统会显示一长串Token字符串,这个字符串只显示一次,务必立即保存到安全位置。

除了API Token之外,还需要获取Zone ID和Record ID。Zone ID可以在域名概述页面的右下角API区域找到,直接复制即可。Record ID需要通过API查询获取,可以使用curl命令调用List DNS Records接口,在返回的JSON数据中找到目标A记录的id字段值。下面是查询记录的命令示例:

curl -s -X GET "https://api.cloudflare.com/client/v4/zones/你的ZoneID/dns_records?name=ddns.ipipp.com&type=A" \
  -H "Authorization: Bearer 你的APIToken" \
  -H "Content-Type: application/json"

返回的JSON中result数组里每条记录都包含一个id字段,把这个值记录下来,后续更新脚本会用到。如果你有多个子域名需要动态解析,每个子域名都对应一个独立的Record ID,需要分别查询保存。建议将这些参数统一放在一个配置文件中管理,方便后续维护和多域名扩展。

二、编写核心脚本:检测IP变化并调用API更新

脚本的核心逻辑分为三步:获取当前公网IP、读取上次记录的IP、比较两者是否一致。如果IP发生变化,就调用Cloudflare API的PATCH接口更新A记录。获取公网IP有多种方式,最常用的是通过外部服务查询,比如访问ipinfo.io或ifconfig.me。这种方式依赖第三方服务可用性,如果这些服务宕机脚本就会失效。更稳妥的做法是同时查询多个源,取第一个有效结果。

下面是一个完整的Shell脚本示例,包含了IP获取、变化检测、API调用和日志记录功能:

#!/bin/bash

# Cloudflare DDNS 自动更新脚本

# ===== 配置区域 =====
API_TOKEN="你的APIToken"
ZONE_ID="你的ZoneID"
RECORD_ID="你的RecordID"
RECORD_NAME="ddns.ipipp.com"
TTL=120
PROXIED=false

# IP缓存文件路径
IP_CACHE="/var/log/cloudflare_ddns/ip_cache.txt"
# 日志文件路径
LOG_FILE="/var/log/cloudflare_ddns/ddns.log"

# 获取当前公网IP
get_current_ip() {
    local ip=""
    # 依次尝试多个IP查询服务
    for url in "https://ipinfo.io/ip" "https://ifconfig.me" "https://api.ipify.org"; do
        ip=$(curl -s --connect-timeout 5 "$url" 2>/dev/null | grep -oE '^[0-9]{1,3}(\.[0-9]{1,3}){3}$')
        if [ -n "$ip" ]; then
            echo "$ip"
            return 0
        fi
    done
    return 1
}

# 获取缓存的IP
get_cached_ip() {
    if [ -f "$IP_CACHE" ]; then
        cat "$IP_CACHE"
    else
        echo ""
    fi
}

# 更新Cloudflare DNS记录
update_dns_record() {
    local new_ip="$1"
    local response
    response=$(curl -s -X PATCH \
        "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${RECORD_ID}" \
        -H "Authorization: Bearer ${API_TOKEN}" \
        -H "Content-Type: application/json" \
        --data "{\"type\":\"A\",\"name\":\"${RECORD_NAME}\",\"content\":\"${new_ip}\",\"ttl\":${TTL},\"proxied\":${PROXIED}}")
    
    local success
    success=$(echo "$response" | grep -o '"success":true')
    if [ -n "$success" ]; then
        return 0
    else
        return 1
    fi
}

# 主逻辑
main() {
    local current_ip cached_ip
    current_ip=$(get_current_ip)
    if [ -z "$current_ip" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] 错误:无法获取公网IP" >> "$LOG_FILE"
        exit 1
    fi
    
    cached_ip=$(get_cached_ip)
    if [ "$current_ip" = "$cached_ip" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] IP未变化:${current_ip}" >> "$LOG_FILE"
        exit 0
    fi
    
    # IP发生变化,执行更新
    if update_dns_record "$current_ip"; then
        echo "$current_ip" > "$IP_CACHE"
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] 更新成功:${cached_ip} -> ${current_ip}" >> "$LOG_FILE"
    else
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] 更新失败:API返回错误" >> "$LOG_FILE"
        exit 1
    fi
}

main

这个脚本的设计有几个关键点值得注意。首先是IP缓存机制,通过将上次成功更新的IP写入文件,下次运行时只需读取文件比较即可,避免每次都查询DNS记录。其次是多源IP查询策略,当第一个服务不可用时自动切换到备用源,大幅提升了脚本在恶劣网络环境下的可靠性。最后是日志记录,每次运行都会写入时间戳和操作结果,方便后续排查问题。

关于TTL值的设置,如果域名开启了Cloudflare代理(橙色云朵),TTL会自动设为Auto,手动设置的值不生效。只有当代理关闭(灰色云朵)时,TTL设置才有效。建议将TTL设置为120秒,这样IP变化后最多两分钟全球DNS就会刷新,对于动态IP场景来说响应速度足够快。如果对实时性要求更高,可以设为60秒,但要注意Cloudflare对A记录最低TTL的限制。

三、配置定时任务与容错机制

脚本编写完成后,需要通过cron定时任务让它自动运行。在Linux系统上执行crontab -e命令编辑定时任务,添加一行配置即可。建议设置为每五分钟执行一次,频率太高会给IP查询服务造成压力,频率太低又可能导致IP变化后长时间无法访问。下面是cron配置示例:

# 每五分钟执行一次DDNS更新
*/5 * * * * /bin/bash /usr/local/bin/cloudflare_ddns.sh >> /var/log/cloudflare_ddns/cron.log 2>&1

除了基本的定时执行,还需要考虑几个容错场景。第一是网络抖动导致IP查询失败,脚本中已经通过多源查询和超时设置处理了这个问题。第二是Cloudflare API临时不可用,可以在update_dns_record函数中增加重试逻辑,连续失败三次才判定为真正失败。第三是并发冲突,如果上一次执行还没结束下一次就启动了,可以通过flock文件锁来防止重复执行。

下面是加入文件锁和重试机制的改进版本关键片段:

# 使用文件锁防止并发执行
LOCK_FILE="/var/lock/cloudflare_ddns.lock"
exec 200>"$LOCK_FILE"
flock -n 200 || {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 警告:另一个实例正在运行,退出" >> "$LOG_FILE"
    exit 0
}

# 带重试的DNS更新函数
update_with_retry() {
    local new_ip="$1"
    local max_retries=3
    local retry=0
    while [ $retry -lt $max_retries ]; do
        if update_dns_record "$new_ip"; then
            return 0
        fi
        retry=$((retry + 1))
        sleep 5
    done
    return 1
}

文件锁通过flock命令实现,200是文件描述符编号,-n参数表示获取锁失败时立即返回而不等待。这样当cron触发新一次执行时,如果上一次还没跑完,新进程会直接退出,不会产生冲突。重试机制在API调用失败时等待5秒后重试,最多尝试三次,能够有效应对Cloudflare API偶发的5xx错误。

对于运行在OpenWrt路由器或NAS设备上的场景,这些设备通常使用BusyBox提供的精简版Shell,flock命令可能不可用。此时可以用PID文件锁替代方案:脚本启动时检查PID文件是否存在且对应进程仍在运行,如果存在就退出,否则写入当前PID继续执行。虽然不如flock可靠,但在资源受限的嵌入式设备上是一个实用的折中方案。

最后建议定期检查日志文件大小,避免长期运行后日志撑满磁盘。可以在脚本末尾加一行简单的日志轮转逻辑,当日志超过一定行数时只保留最新的部分。或者配置logrotate工具统一管理,这样更加规范。整个方案搭建完成后,你的动态域名解析服务就能稳定运行,IP变化后几分钟内自动完成更新,无需任何人工干预。

Cloudflare DDNS动态域名解析Shell脚本修改时间:2026-08-25 06:31:13

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。