动态 DNS:家用宽带也能有个固定域名
家庭宽带的公网 IP 会变(重拨或运营商定期回收)。DDNS 让你用一个固定域名访问它,每次 IP 变了自动更新解析。
一、先确认有没有公网 IP
很多宽带其实没有公网 IPv4 了(运营商用 CGNAT)。先测:
# 1. 看路由器 WAN 口获取的 IP
# 登录路由器管理界面看
# 2. 看外网看到的 IP
curl -s ifconfig.me
curl -s ip.sb
# 3. 两者一致 → 有公网 IP
# 路由器是 100.x / 10.x / 172.16-31.x → 大概率是内网(CGNAT)如果没有公网 IPv4:
- 打电话给运营商申请(部分可申请到,且可能收费);
- 用 IPv6(现在家宽普遍有 IPv6,且是公网);
- 改用内网穿透(frp / Cloudflare Tunnel)或组网(Tailscale)。
二、DDNS 的原理
定时检查本机公网 IP
→ 与 DNS 记录里的值比较
→ 不同则调用 API 更新 A/AAAA 记录TTL 要设短(60~300 秒),否则 IP 变了要等很久才生效。
三、用 Cloudflare API 自己实现
准备
- 在 Cloudflare 控制台创建 API Token(权限:
Zone.DNS编辑); - 记下 Zone ID(域名概览页右下角);
- 先在控制台手动建一条 A 记录(比如
home.bzii.cn)。
脚本
#!/usr/bin/env bash
# /opt/scripts/ddns.sh
set -euo pipefail
CF_TOKEN="你的API Token"
ZONE_ID="你的Zone ID"
RECORD_NAME="home.bzii.cn"
TTL=120
# 1. 获取当前公网 IP
IP=$(curl -s --max-time 10 https://api.ipify.org)
if [ -z "$IP" ]; then echo "获取 IP 失败"; exit 1; fi
# 2. 查 DNS 里的记录 ID 和当前值
RESP=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$RECORD_NAME" \
-H "Authorization: Bearer $CF_TOKEN" -H "Content-Type: application/json")
REC_ID=$(echo "$RESP" | jq -r ".result[0].id")
CUR_IP=$(echo "$RESP" | jq -r ".result[0].content")
# 3. 相同就不动
if [ "$IP" = "$CUR_IP" ]; then
echo "[$(date)] IP 未变: $IP"
exit 0
fi
# 4. 不同则更新
curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$REC_ID" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data "{\"content\":\"$IP\",\"ttl\":$TTL}" > /dev/null
echo "[$(date)] 已更新 $RECORD_NAME: $CUR_IP → $IP"chmod +x /opt/scripts/ddns.sh
sudo /opt/scripts/ddns.sh
dig +short home.bzii.cn定时执行
crontab -e
*/5 * * * * /opt/scripts/ddns.sh >> /var/log/ddns.log 2>&1四、IPv6 版本
家宽的 IPv6 通常每个设备都有一个公网地址,而且前缀也会变。做法类似,但要更新 AAAA 记录:
# 获取本机 IPv6(全球单播地址)
IP6=$(ip -6 addr show scope global | grep inet6 | awk '{print $2}' | cut -d/ -f1 | head -1)IPv6 地址很长且会变,用 DDNS 管理是唯一实用的方式。好处是不需要 NAT、不需要端口映射。
五、路由器自带 DDNS
很多路由器(华硕、小米、OpenWrt)内置 DDNS 客户端,支持花生壳、No-IP、DynDNS 等。
优点:不用自己写脚本,路由器上直接配。 缺点:只能用它们支持的第三方服务(域名不是自己的),或者部分支持 Cloudflare。
OpenWrt 用户可以直接装 ddns-scripts + ddns-scripts-cloudflare:
opkg update
opkg install ddns-scripts ddns-scripts-cloudflare luci-app-ddns六、现成工具:ddclient
sudo apt install -y ddclient# /etc/ddclient.conf
protocol=cloudflare, \
use=web, web=https://api.ipify.org, \
zone=www.bzii.cn, \
login=token, \
password=你的API Token, \
home.bzii.cnsudo systemctl enable --now ddclient
sudo ddclient -verbose -noquiet -force # 手动触发一次七、安全注意
把家里的服务暴露到公网,风险不小:
- API Token 权限要最小化:只给该域名的 DNS 编辑权限;
- 脚本权限 600,别让其他用户读到 token:
chmod 600 /opt/scripts/ddns.sh- 路由器只映射必要端口,且服务本身要有认证;
- 用非标准端口(比如外部 2222 → 内部 22);
- 定期看日志,确认没有异常访问。
更推荐的做法:根本不暴露,用 Tailscale 组网。 自己远程访问家里的机器,组网方案比 DDNS + 端口映射安全得多,也更简单。
八、什么时候该用 DDNS
| 场景 | 建议 |
|---|---|
| 自己远程访问家里 NAS / 下载机 | Tailscale 更好 |
| 要给别人提供访问(如私人 Git) | DDNS + 端口映射 |
| 家里跑个小型站点 | DDNS + 反向代理 + HTTPS |
| 需要固定 IP 收 webhook | Cloudflare Tunnel |
九、排错
| 现象 | 排查 |
|---|---|
| 域名解析到旧 IP | TTL 太长,或脚本没跑 |
| 脚本报 401 | Token 错误或权限不足 |
| 脚本报 找不到记录 | 记录名写错,或还没手动创建 |
| IP 一直没变但外网访问不了 | 可能是 CGNAT,没有真公网 IP |
| 更新成功但访问不了 | 路由器端口映射没配 |
# 看脚本日志
tail -20 /var/log/ddns.log
# 确认当前解析
dig +short home.bzii.cn
# 确认实际公网 IP
curl -s ifconfig.meDDNS 是「没有固定 IP 时的折中方案」。在用它之前,先问一句:我真的需要把服务暴露到公网吗?
