DDNS动态域名解析方案对比与实战配置

本文详解DDNS工作原理、主流方案对比,以及在各种场景下的实战配置。

前言

家里的宽带IP是动态的,每次重启光猫IP就变了。想从外面访问家里的服务器,怎么办?

DDNS(Dynamic DNS) 就是解决这个问题的:自动检测IP变化,自动更新域名解析。

今天来聊聊各种DDNS方案的选择和配置。


一、DDNS原理

1.1 动态IP的问题

运营商给家庭宽带分配的通常是动态公网IP:

  • IP地址会变化(重启、租期到期)
  • 无法用固定IP访问

1.2 DDNS如何解决

复制代码
┌─────────────┐    IP变化     ┌─────────────┐
│   家庭路由   │ ──检测到──→  │ DDNS客户端  │
│  IP:1.2.3.4 │              │            │
└─────────────┘              └──────┬──────┘
                                    │ 调用API更新
                                    ↓
                            ┌─────────────┐
                            │  DNS服务商   │
                            │ example.com │
                            │  → 1.2.3.4  │
                            └─────────────┘

工作流程:

  1. DDNS客户端定期检测本机公网IP
  2. 发现IP变化后,调用DNS服务商API
  3. 更新域名的A记录
  4. 域名始终指向当前IP

二、DDNS方案对比

2.1 免费DDNS服务

服务 域名 优点 缺点
No-IP xxx.ddns.net 免费、客户端多 需每月确认
DuckDNS xxx.duckdns.org 完全免费 域名不好看
Dynu xxx.dynu.net 免费、功能全 速度一般
FreeDNS 多种子域名 选择多 稳定性一般

2.2 国内DNS服务商

服务商 支持DDNS API调用 适合场景
阿里云DNS 有官方API 有自己域名
腾讯云DNS 有官方API 有自己域名
Cloudflare 有API 海外访问
华为云DNS 有API 华为云用户

2.3 路由器内置

很多路由器/光猫内置DDNS功能:

  • 花生壳
  • No-IP
  • 自定义

三、阿里云DDNS配置

3.1 前置条件

  1. 有一个域名(托管在阿里云)
  2. 创建AccessKey

3.2 获取AccessKey

  1. 登录阿里云控制台
  2. 右上角头像 → AccessKey管理
  3. 创建AccessKey,保存好ID和Secret

3.3 使用Shell脚本

bash 复制代码
#!/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

# 获取当前公网IP
get_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() {
    local record_id=$1
    local ip=$2
    aliyun 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" ]; then
    echo "$(date): IP changed from $dns_ip to $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"
else
    echo "$(date): IP unchanged ($current_ip)"
fi

3.4 使用第三方工具(推荐)

ddns-go 是一个优秀的开源DDNS工具:

bash 复制代码
# 下载
wget https://github.com/jeessy2/ddns-go/releases/download/v5.6.0/ddns-go_5.6.0_linux_x86_64.tar.gz
tar xf ddns-go*.tar.gz

# 运行
./ddns-go

# 访问 http://localhost:9876 配置

ddns-go优点:

  • Web界面配置
  • 支持多种DNS服务商
  • 支持IPv6
  • 支持Webhook通知

四、腾讯云DDNS配置

4.1 获取密钥

  1. 登录腾讯云控制台
  2. 访问密钥管理
  3. 创建API密钥

4.2 Python脚本

python 复制代码
#!/usr/bin/env python3
# tencent_ddns.py

import json
import requests
from tencentcloud.common import credential
from tencentcloud.dnspod.v20210323 import dnspod_client, models

# 配置
SECRET_ID = "your_secret_id"
SECRET_KEY = "your_secret_key"
DOMAIN = "example.com"
SUBDOMAIN = "home"

def get_current_ip():
    """获取当前公网IP"""
    services = [
        'http://ip.3322.net',
        'http://ifconfig.me',
        'http://ipinfo.io/ip'
    ]
    for service in services:
        try:
            resp = requests.get(service, timeout=5)
            return resp.text.strip()
        except:
            continue
    return None

def get_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)
    if resp.RecordList:
        return resp.RecordList[0]
    return None

def update_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()
    
    if record and record.Value != current_ip:
        update_dns_record(record.RecordId, current_ip)
    else:
        print(f"IP unchanged: {current_ip}")

4.3 安装依赖

bash 复制代码
pip install tencentcloud-sdk-python requests

五、Cloudflare DDNS配置

5.1 获取API Token

  1. 登录Cloudflare
  2. My Profile → API Tokens
  3. Create Token → Edit zone DNS

5.2 使用Shell脚本

bash 复制代码
#!/bin/bash
# cloudflare-ddns.sh

# 配置
CF_API_TOKEN="your_api_token"
CF_ZONE_ID="your_zone_id"
CF_RECORD_NAME="home.example.com"

# 获取当前IP
CURRENT_IP=$(curl -s http://ipinfo.io/ip)

# 获取DNS记录ID
RECORD_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记录的IP
DNS_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')

# 更新DNS
if [ "$CURRENT_IP" != "$DNS_IP" ]; then
    echo "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"
else
    echo "IP unchanged: $CURRENT_IP"
fi

六、定时任务配置

6.1 Cron定时执行

bash 复制代码
# 编辑crontab
crontab -e

# 每5分钟检查一次
*/5 * * * * /path/to/ddns-script.sh >> /var/log/ddns.log 2>&1

6.2 Systemd Timer

bash 复制代码
# /etc/systemd/system/ddns.service
[Unit]
Description=DDNS Update Service

[Service]
Type=oneshot
ExecStart=/path/to/ddns-script.sh

# /etc/systemd/system/ddns.timer
[Unit]
Description=DDNS Update Timer

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target
bash 复制代码
systemctl enable ddns.timer
systemctl start ddns.timer

七、路由器DDNS配置

7.1 OpenWrt内置DDNS

bash 复制代码
# 安装ddns脚本
opkg update
opkg install ddns-scripts luci-app-ddns

# Web界面配置
# Services → Dynamic DNS

7.2 常见路由器

华硕路由器:

  • 外部网络 → DDNS → 选择服务商配置

小米路由器:

  • 高级设置 → DDNS → 配置账号

TP-Link:

  • 应用管理 → DDNS → 配置

八、没有公网IP怎么办

8.1 检测是否有公网IP

bash 复制代码
# 方法1:比较内外网IP
# 路由器WAN口IP
route -n | grep UG

# 公网IP
curl ip.3322.net

# 如果两个IP不一样,说明没有公网IP

8.2 替代方案

如果运营商没有给公网IP(大内网),DDNS就没用了。替代方案:

  1. 向运营商申请公网IP:打客服电话,说要监控/远程办公

  2. 使用组网软件:如星空组网,不需要公网IP也能远程访问

    • 安装客户端
    • 登录同一账号
    • 通过虚拟IP访问
  3. 内网穿透:frp、ngrok等


九、DDNS + 端口映射

有了DDNS域名,还需要配置端口映射才能访问内网服务:

复制代码
互联网 → home.example.com:8080 → 路由器:8080 → 内网服务器:80

路由器端口映射配置:

  • 外部端口:8080
  • 内部IP:192.168.1.100
  • 内部端口:80
  • 协议:TCP

安全建议:

  • 不要映射22端口到公网
  • 使用非标准端口
  • 配合fail2ban等安全措施
  • 或者用组网软件替代端口映射,更安全

十、总结

DDNS方案选择建议:

场景 推荐方案
快速体验 DuckDNS(完全免费)
有自己域名 ddns-go + 阿里云/腾讯云
海外访问 Cloudflare
路由器方案 OpenWrt ddns-scripts
无公网IP 组网软件(如星空组网)

DDNS虽然能解决动态IP问题,但还要配合端口映射使用,有一定安全风险。如果不想折腾,直接用组网软件可能是更简单的选择。


参考资料

  1. ddns-go: https://github.com/jeessy2/ddns-go
  2. 阿里云DNS API: https://help.aliyun.com/document_detail/29739.html
  3. Cloudflare API: https://api.cloudflare.com/

💡 提示:DDNS更新有延迟(取决于TTL设置),建议TTL设置短一些(如120秒)。但太短会增加DNS查询次数。

相关推荐
树℡独7 小时前
ns-3仿真之应用层(五)
服务器·网络·tcp/ip·ns3
zhang133830890758 小时前
CG-09H 超声波风速风向传感器 加热型 ABS材质 重量轻 没有机械部件
大数据·运维·网络·人工智能·自动化
酣大智9 小时前
接口模式参数
运维·网络·网络协议·tcp/ip
24zhgjx-lxq10 小时前
华为ensp:MSTP
网络·安全·华为·hcip·ensp
ling___xi10 小时前
《计算机网络》计网3小时期末速成课各版本教程都可用谢稀仁湖科大版都可用_哔哩哔哩_bilibili(笔记)
网络·笔记·计算机网络
REDcker10 小时前
Linux 文件描述符与 Socket 选项操作详解
linux·运维·网络
Up九五小庞11 小时前
用arpspoof实现100%批量切断192.168.110.10 - 192.168.110.100 断网(双向欺骗)--九五小庞
网络·开源
躺柒11 小时前
读数字时代的网络风险管理:策略、计划与执行04风险指引体系
大数据·网络·信息安全·数字化·网络管理·网络风险管理
独角鲸网络安全实验室11 小时前
本地信任成“致命漏洞”:数千Clawdbot Agent公网裸奔,供应链与内网安全告急
网络·网关·安全·php·漏洞·clawdbot·信任机制漏洞
ai_xiaogui11 小时前
Tailscale实现家庭与公司网络双向通信教程:子网路由配置详解
网络·tailscale·双向通信·子网路由配置详解·tailscale双向互访