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查询次数。

相关推荐
优化Henry10 分钟前
光路异常告警排查实战:LTE室分与5G小区两个案例解析
运维·网络·学习·5g·tdd
Apipi*20 分钟前
30天速通Linux 第九章Linux网络编程
linux·运维·网络
隐擎fox28 分钟前
深入网络风控底层:解密 IP 信誉评分模型、ASN 属性判定与多租户原生网络隔离架构
网络·爬虫·网络协议·tcp/ip·架构·跨境电商·指纹浏览器
ESDWAN1 小时前
跨境网络频繁掉线怎么排查?从企业内网到 SD-WAN 链路的故障诊断
开发语言·网络·php
青瓦梦滋1 小时前
【在线五子棋对战】session
服务器·网络·网络协议
资深电气设计1 小时前
数据中心低压盘柜选型逻辑解析:ABB技术体系的参考价值
网络·创业创新·业界资讯
牧羊人.3331 小时前
动手学深度学习 07|Resnet网络与迁移学习
网络·人工智能·深度学习·神经网络·算法·cnn·迁移学习
北京中科新远科技2 小时前
AI网络设备兼容性验收实战:交换机、网卡、线缆与光模块逐层检查
网络
Java后端的Ai之路2 小时前
昇腾NPU显存管理避坑指南:从npu-smi输出精准识别空闲卡的底层逻辑与实战
服务器·网络·数据库·npu·大模型服务