TI CC2531 USB Dongle硬件解析与ZigBee开发实战指南
2026/7/26 2:00:16
本文详解DDNS工作原理、主流方案对比,以及在各种场景下的实战配置。
家里的宽带IP是动态的,每次重启光猫IP就变了。想从外面访问家里的服务器,怎么办?
DDNS(Dynamic DNS)就是解决这个问题的:自动检测IP变化,自动更新域名解析。
今天来聊聊各种DDNS方案的选择和配置。
运营商给家庭宽带分配的通常是动态公网IP:
┌─────────────┐ IP变化 ┌─────────────┐ │ 家庭路由 │ ──检测到──→ │ DDNS客户端 │ │ IP:1.2.3.4 │ │ │ └─────────────┘ └──────┬──────┘ │ 调用API更新 ↓ ┌─────────────┐ │ DNS服务商 │ │ example.com │ │ → 1.2.3.4 │ └─────────────┘工作流程:
| 服务 | 域名 | 优点 | 缺点 |
|---|---|---|---|
| No-IP | xxx.ddns.net | 免费、客户端多 | 需每月确认 |
| DuckDNS | xxx.duckdns.org | 完全免费 | 域名不好看 |
| Dynu | xxx.dynu.net | 免费、功能全 | 速度一般 |
| FreeDNS | 多种子域名 | 选择多 | 稳定性一般 |
| 服务商 | 支持DDNS | API调用 | 适合场景 |
|---|---|---|---|
| 阿里云DNS | ✅ | 有官方API | 有自己域名 |
| 腾讯云DNS | ✅ | 有官方API | 有自己域名 |
| Cloudflare | ✅ | 有API | 海外访问 |
| 华为云DNS | ✅ | 有API | 华为云用户 |
很多路由器/光猫内置DDNS功能:
#!/bin/bash# aliyun-ddns.sh# 配置区ACCESS_KEY_ID="your_access_key_id"ACCESS_KEY_SECRET="your_access_key_secret"DOMAIN="example.com"SUBDOMAIN="home"# 完整域名是 home.example.com# 获取当前公网IPget_current_ip(){curl-s http://ip.3322.net||\curl-s http://ifconfig.me||\curl-s http://ipinfo.io/ip}# 获取当前DNS记录get_dns_ip(){aliyun alidns DescribeDomainRecords\--DomainName"$DOMAIN"\--RRKeyWord"$SUBDOMAIN"\--Type"A"2>/dev/null|\jq -r'.DomainRecords.Record[0].Value'}# 更新DNS记录update_dns(){localrecord_id=$1localip=$2aliyun alidns UpdateDomainRecord\--RecordId"$record_id"\--RR"$SUBDOMAIN"\--Type"A"\--Value"$ip"}# 主逻辑current_ip=$(get_current_ip)dns_ip=$(get_dns_ip)if["$current_ip"!="$dns_ip"];thenecho"$(date): IP changed from$dns_ipto$current_ip"record_id=$(aliyun alidns DescribeDomainRecords\--DomainName"$DOMAIN"\--RRKeyWord"$SUBDOMAIN"|\jq -r'.DomainRecords.Record[0].RecordId')update_dns"$record_id""$current_ip"echo"DNS updated successfully"elseecho"$(date): IP unchanged ($current_ip)"fiddns-go是一个优秀的开源DDNS工具:
# 下载wgethttps://github.com/jeessy2/ddns-go/releases/download/v5.6.0/ddns-go_5.6.0_linux_x86_64.tar.gztarxf ddns-go*.tar.gz# 运行./ddns-go# 访问 http://localhost:9876 配置ddns-go优点:
#!/usr/bin/env python3# tencent_ddns.pyimportjsonimportrequestsfromtencentcloud.commonimportcredentialfromtencentcloud.dnspod.v20210323importdnspod_client,models# 配置SECRET_ID="your_secret_id"SECRET_KEY="your_secret_key"DOMAIN="example.com"SUBDOMAIN="home"defget_current_ip():"""获取当前公网IP"""services=['http://ip.3322.net','http://ifconfig.me','http://ipinfo.io/ip']forserviceinservices:try:resp=requests.get(service,timeout=5)returnresp.text.strip()except:continuereturnNonedefget_dns_record():"""获取DNS记录"""cred=credential.Credential(SECRET_ID,SECRET_KEY)client=dnspod_client.DnspodClient(cred,"")req=models.DescribeRecordListRequest()req.Domain=DOMAIN req.Subdomain=SUBDOMAIN resp=client.DescribeRecordList(req)ifresp.RecordList:returnresp.RecordList[0]returnNonedefupdate_dns_record(record_id,ip):"""更新DNS记录"""cred=credential.Credential(SECRET_ID,SECRET_KEY)client=dnspod_client.DnspodClient(cred,"")req=models.ModifyRecordRequest()req.Domain=DOMAIN req.RecordId=record_id req.SubDomain=SUBDOMAIN req.RecordType="A"req.RecordLine="默认"req.Value=ip client.ModifyRecord(req)print(f"Updated{SUBDOMAIN}.{DOMAIN}to{ip}")if__name__=="__main__":current_ip=get_current_ip()record=get_dns_record()ifrecordandrecord.Value!=current_ip:update_dns_record(record.RecordId,current_ip)else:print(f"IP unchanged:{current_ip}")pipinstalltencentcloud-sdk-python requests#!/bin/bash# cloudflare-ddns.sh# 配置CF_API_TOKEN="your_api_token"CF_ZONE_ID="your_zone_id"CF_RECORD_NAME="home.example.com"# 获取当前IPCURRENT_IP=$(curl-s http://ipinfo.io/ip)# 获取DNS记录IDRECORD_ID=$(curl-s -X GET"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records?name=$CF_RECORD_NAME"\-H"Authorization: Bearer$CF_API_TOKEN"\-H"Content-Type: application/json"|jq -r'.result[0].id')# 获取当前DNS记录的IPDNS_IP=$(curl-s -X GET"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records/$RECORD_ID"\-H"Authorization: Bearer$CF_API_TOKEN"\-H"Content-Type: application/json"|jq -r'.result.content')# 更新DNSif["$CURRENT_IP"!="$DNS_IP"];thenecho"Updating DNS:$DNS_IP->$CURRENT_IP"curl-s -X PUT"https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records/$RECORD_ID"\-H"Authorization: Bearer$CF_API_TOKEN"\-H"Content-Type: application/json"\--data"{\"type\":\"A\",\"name\":\"$CF_RECORD_NAME\",\"content\":\"$CURRENT_IP\",\"ttl\":120,\"proxied\":false}"echo"DNS updated"elseecho"IP unchanged:$CURRENT_IP"fi# 编辑crontabcrontab-e# 每5分钟检查一次*/5 * * * * /path/to/ddns-script.sh>>/var/log/ddns.log2>&1# /etc/systemd/system/ddns.service[Unit]Description=DDNS Update Service[Service]Type=oneshotExecStart=/path/to/ddns-script.sh# /etc/systemd/system/ddns.timer[Unit]Description=DDNS Update Timer[Timer]OnBootSec=1minOnUnitActiveSec=5min[Install]WantedBy=timers.targetsystemctlenableddns.timer systemctl start ddns.timer# 安装ddns脚本opkg update opkginstallddns-scripts luci-app-ddns# Web界面配置# Services → Dynamic DNS华硕路由器:
小米路由器:
TP-Link:
# 方法1:比较内外网IP# 路由器WAN口IProute -n|grepUG# 公网IPcurlip.3322.net# 如果两个IP不一样,说明没有公网IP如果运营商没有给公网IP(大内网),DDNS就没用了。替代方案:
向运营商申请公网IP:打客服电话,说要监控/远程办公
使用组网软件:如星空组网,不需要公网IP也能远程访问
内网穿透:frp、ngrok等
有了DDNS域名,还需要配置端口映射才能访问内网服务:
互联网 → home.example.com:8080 → 路由器:8080 → 内网服务器:80路由器端口映射配置:
安全建议:
DDNS方案选择建议:
| 场景 | 推荐方案 |
|---|---|
| 快速体验 | DuckDNS(完全免费) |
| 有自己域名 | ddns-go + 阿里云/腾讯云 |
| 海外访问 | Cloudflare |
| 路由器方案 | OpenWrt ddns-scripts |
| 无公网IP | 组网软件(如星空组网) |
DDNS虽然能解决动态IP问题,但还要配合端口映射使用,有一定安全风险。如果不想折腾,直接用组网软件可能是更简单的选择。
💡提示:DDNS更新有延迟(取决于TTL设置),建议TTL设置短一些(如120秒)。但太短会增加DNS查询次数。