部署自己的动态DNS解析服务器.

 

部署原因

 

dnspod或者阿里云或者其他DDNS解析,ttl值基本上是600,

也就是缓存10分钟.

也就是你提交了IP变动,也需要10分钟其他人才会刷新.

即使你在这些平台花钱了,只能缩短ttl到60,也就是1分钟缓存.

 

如果想ttl变成1,也就是1秒,那么就要自己部署.

 

 

PDNS

 

安装

一般一键安装即可,各大linux软件包都有,直接请求.

可以用文件存解析,也可以用数据库.

我用的mysql,需要多安装一个pdns-backend-mysql 

sudo apt install pdns-server pdns-backend-mysql 

 

设置

一般就是指定下数据库,还有监听IP和端口

#指定mysql,数据库需要自己手动创建.

launch=gmysql
gmysql-host=127.0.0.1
gmysql-port=3307
gmysql-user=powerdns
gmysql-password=Password123
gmysql-dbname=powerdns


#设置监听IP范围和端口

local-address=0.0.0.0, ::1
local-port=53

 

 

开机启动

sudo systemctl enable pdns
sudo systemctl start pdns

#查看状态
sudo systemctl status pdns 

 

开放端口

也就是53端口,除了系统还需要在VPS控制面板放行.

 

 

PowerAdmin

这个是一个web管理端. 有python也有php的还有其他开发语言(作者都不是同一个人,也不是一个团队).

 

我装的是PHP版本,而且是旧版本,因为新版本要php8.1 我服务器核心php版本是7.4

https://github.com/poweradmin/poweradmin/tree/v3.4.2

 

如果你不想装poweradmin,可以只导入PDNS数据库文件

https://github.com/poweradmin/poweradmin/blob/v3.4.2/sql/pdns/4.7.x/schema.mysql.sql

保证PDNS先运行.

 

建议就是poweradmin先安装,安装的时候web简单配置,自动导入数据库.

后续用不太上,后续禁用即可.

 

 

部署解析

 

 

我单独阿里云注册一个了纯数字xyz域名.60元还是多少10年有效期.

在阿里云解析里面指定域名DNS服务器为我域名
NS1.getce.cn和NS2.getce.cn 这两个都指向我服务器IP(只有一个服务器,所以是同一个IP).



poweradmin添加域名

 

添加模板(可选)

 

添加域名

 

 

添加解析

如果前面添加了模板,那么添加域名的时候,自动有前三条.

SOA 第一个NS1.getce.cn 是NS服务器,

第二个y.yge.me 实际上是邮箱,这里用点代替@,

第三个数字是序列号,20250524是日期,11是计数,每更新一次都会自动+1.

 

测试

可以用dig @服务器ip -p 端口 AAAA/SOA/A/NS 域名 查询看看生效情况.

一般新域名解析需要72小时通告全球(实际上半小时即可,最晚不超过72小时)

也可以用https://dnschecker.org查询

 

 

 

 

意外情况

我还没开始用,腾讯云就封停了53端口.

还发短信告诉我, 是"接到用户举报",所以关停了53端口.

后面我用我朋友海外服务器,做了DNS转发.核心还在我腾讯云服务器上.

DNS转发(可选)

如果服务器在国外直接53端口出来即可.我实在没办法,腾讯不给开放53,要转发.

我在我朋友海外服务器上安装了pdns-recursor.

改配置文件,

# /etc/powerdns/recursor.conf
local-address = 0.0.0.0, ::
local-port = 53
forward-zones = 5043240.xyz=106.55.33.60:54
allow-from = 0.0.0.0/0, ::/0  # 允许所有客户端(生产环境建议限制 IP 范围)

特别是5043240.xyz=106.55.33.60:54
将5043240.xyz所有解析全部指向106.55.33.60:54 

 

部署DDNS

控制pdns有两种方式,一种是API,一种是直接操作数据库.我选择的后者.能用就行.比较好开发.

 

web后台

我web后台是thinkphp,在数据库配置文件中添加powerdns数据库配置,并添加一个模型.

<?php

namespace app\common\model\powerdns;
use app\common\model\BaseModel;
class Records extends BaseModel
{
    protected $connection = 'powerdns';
    protected $name = 'records';
    // 开启自动写入时间戳字段
    protected $autoWriteTimestamp = false;
    // 定义时间戳字段名
    protected $createTime = false;
    protected $updateTime = false;
}

添加一个API接口,后台接收了直接写入数据库.

 

注意要更新下SOA的系列号.

    function updateSOARecord($soaRecord) {
        // 分割 SOA 记录的各个部分
        $parts = explode(' ', $soaRecord);
        if (count($parts) != 7) {
            throw new Exception("Invalid SOA record format");
        }

        // 提取旧的 Serial
        $oldSerial = $parts[2];

        // 分割日期部分和序号
        $datePart = substr($oldSerial, 0, 8);
        $sequence = intval(substr($oldSerial, 8, 2));

        // 获取今日日期
        $today = date("Ymd");

        // 判断并生成新序列号
        if ($datePart === $today) {
            // 当天递增序号(00-99循环)
            $newSequence = ($sequence + 1) % 100;
        } else {
            // 非当天重置序号
            $newSequence = 0;
        }

        // 组合新序列号
        $newSerial = $today . str_pad($newSequence, 2, '0', STR_PAD_LEFT);

        // 更新 SOA 记录中的 Serial
        $parts[2] = $newSerial;

        // 重新组合 SOA 记录
        return implode(' ', $parts);
    }

 

客户端部分

 

如何提交

 

有两种常用方式

简单一点就是计划任务.好处可以适配任何linux系统. 特别我主要用在openwrt路由系统.缺点就是计划任务最短间隔是1分钟.

另外一种就是热拔插事件.好处就是响应极快.一旦获取IP变动就请求提交到web服务器.但缺点也非常明显,要网口断开或者连接才会触发热拔插.ipv6刷新不触发.

 

所以上面两个方法我都没用.

我用的自写服务,监控IPV6变化.

 

这是deepseek的方法,通过 ip monitor 结合 systemd 服务 实现IPv6地址变更时自动触发脚本

#!/bin/bash

# 监控 eth0 的地址变化事件
ip monitor address dev eth0 | while read -r line; do
    # 检测到新增IPv6地址时(包含 "inet6" 和 "valid_lft" 关键字)
    if echo "$line" | grep -q "inet6.*valid_lft"; then
        # 延迟1秒等待地址稳定(可选)
        sleep 1
        # 执行更新脚本
        /root/post_ipv6.sh
    fi
done

添加服务并开机启动

# /etc/systemd/system/ipv6-monitor.service
# systemctl daemon-reload
# systemctl enable --now ipv6-monitor.service


[Unit]
Description=IPv6 Address Change Monitor
After=network.target

[Service]
ExecStart=/usr/local/bin/ipv6-monitor.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

 

 

 

如何获取IP

 

有个LINUX系统通用的IP获取命令就是ip addr show [设备名] 然后过滤下就能获取到IP.

openwrt还有uci命令. ip addr show 方式更通用,甚至安卓系统也可以.

下面是我的/root/post_ipv6.sh脚本, 如果IPV4稍微调整下即可.

这个脚本可以用于openwrt/安卓手机

#!/bin/bash



# 设备名,自己可以先用ip -6 addr show 看看哪个设备名对应公网IP能被外部ping通,那么指定它的设备名
# 比如路由器拨号的一般是pppoe-wan
dev_name='eth0'


# 子域名 baidu 就是 baidu.5043240.xyz
sub_domian_name="baidu"








#############################################################################################################################

# 定义缓存文件路径
cache_file="/tmp/ipv6_addresses_cache"

# 提交到Web后台参数
url="https://api.getce.cn/v1/tools/ddns.html"
appid="***********************"
secret="*************************"


# 获取IPv6地址列表
ipv6_addresses=$(ip -6 addr show $dev_name | grep 'inet6'| grep '240' | awk '{print $2}' | cut -d/ -f1 | head -n1)

# 如果 ipv6_addresses 为空,则尝试不指定设备获取一个公网IPV6
if [ -z "$ipv6_addresses" ]; then
    ipv6_addresses=$(ip -6 addr show | grep 'inet6'| grep '240' | awk '{print $2}' | cut -d/ -f1 | head -n1)
fi


echo "获取的地址:$ipv6_addresses"



# 读取缓存内容
if [ -f "$cache_file" ]; then
  cached_ipv6_addresses=$(cat "$cache_file")
else
  cached_ipv6_addresses=""
fi

# 比较新的IPv6地址列表与缓存内容
if [ "$ipv6_addresses" == "$cached_ipv6_addresses" ]; then
  echo "IPV6地址未变化,无需更新."
else


  # 发送POST请求
  response=$(curl -X POST -s -o /dev/null -w "%{http_code}" -d "appid=${appid}" -d "secret=${secret}" -d "tools_name=${sub_domian_name}" -d "ip=${ipv6_addresses}" "$url")

  echo "HTTP response code: $response"

  # 检查HTTP响应码,并假设200表示成功(你应该解析JSON响应来确认)
  if [ "$response" -eq 200 ]; then
    # 更新缓存文件
	echo "$ipv6_addresses" > "$cache_file"
    echo "提交成功."
  else
    echo "提交失败."
  fi
fi

 

最终效果

dhcpv6更新ip->ipv6-monitor.sh瞬间感知->post_ipv6.sh 提交IP ->web后台写入pdns数据库.->pdns更新.

大概2-3秒即可完成全球刷新.