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

admin

本文详解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 │

└─────────────┘

工作流程:

DDNS客户端定期检测本机公网IP

发现IP变化后,调用DNS服务商API

更新域名的A记录

域名始终指向当前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 前置条件

有一个域名(托管在阿里云)

创建AccessKey

3.2 获取AccessKey

登录阿里云控制台

右上角头像 → AccessKey管理

创建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 获取密钥

登录腾讯云控制台

访问密钥管理

创建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

登录Cloudflare

My Profile → API Tokens

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就没用了。替代方案:

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

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

安装客户端

登录同一账号

通过虚拟IP访问

内网穿透: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问题,但还要配合端口映射使用,有一定安全风险。如果不想折腾,直接用组网软件可能是更简单的选择。

参考资料

ddns-go: https://github.com/jeessy2/ddns-go

阿里云DNS API: https://help.aliyun.com/document_detail/29739.html

Cloudflare API: https://api.cloudflare.com/

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

Copyright © 2088 中国战将网 - 顶级游戏活动平台 All Rights Reserved.
友情链接