腾讯云动态域名解析DDNS操作记录

  昨天打电话跟电信申请了公网ip,竟然真的成功了,过程也很顺利。拿到的公网ip一般是动态的,所以需要配置DDNS(动态域名解析),将动态的ip映射成域名,外网访问时只需通过输入域名,而无需关心ip是否变动。可以看出,DDNS需要设备在内网处理(来获取出网口ip),并且需要一个域名。

  尽管我有域名和树莓派可以实现独立DDNS,第一选择还是采用路由器自带的花生壳域名服务,因为便捷,很可惜没有成功,转而采用自己实现的方法。域名沿用之前购买的腾讯云服务的DNSPOD,跟AI交流了一下,整理了以下这段python代码,在树莓派上运行,即可实现DDNS。

Tip:有了公网 IP 搭配 DDNS,就能在外网随时随地访问家里的各类服务。比如在外远程登录家里的设备做运维,访问 NAS 调取家里存的照片、电影与文档,跑个人博客、私人笔记服务、下载机、智能家居控制后台,在外操控 Home‑Assistant 管理全屋 IoT 设备,搭建私人网盘替代公共云盘,还可以做远程监控、内网穿透备选、自建游戏服务器。以前实现我的Home‑Assistant公网访问需要依赖公网的服务器和Frp,现在可以更直接简洁了。

具体步骤为:

  1. 账号中心获取腾讯云 API 密钥(SecretID和SecretKey)
  2. 云解析DNS控制台添加解析记录,ip可以先随便填一个,比如8.8.8.8。
  3. 在树莓派执行命令pip install tencentcloud-sdk-python
  4. 新建python文件,粘贴并运行以下代码。
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.dnspod.v20210323 import dnspod_client, models
import requests
from datetime import datetime


SECRET_ID = "AKID***********"
SECRET_KEY = "***************"

DOMAIN = "colorfulife.site" #你的域名
SUBDOMAIN = "anyword" #与前文设置的解析记录对应
RECORD_TYPE = "A"
RECORD_LINE = "默认"


def log(msg):
    print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {msg}")

def get_public_ip():
    """获取本机公网IPv4,多接口容错"""
    urls = [
        "https://api.ipify.org",
        "https://ipv4.icanhazip.com",
        "https://ifconfig.me/ip"
    ]
    for url in urls:
        try:
            ip = requests.get(url, timeout=5).text.strip()
            if ip.count(".") == 3:
                return ip
        except Exception:
            continue
    raise Exception("无法获取公网IP")

def main():
    cred = credential.Credential(SECRET_ID, SECRET_KEY)
    httpProfile = HttpProfile()
    httpProfile.endpoint = "dnspod.tencentcloudapi.com"
    clientProfile = ClientProfile()
    clientProfile.httpProfile = httpProfile
    client = dnspod_client.DnspodClient(cred, "", clientProfile)

    # 1 获取公网IP
    try:
        new_ip = get_public_ip()
    except Exception as e:
        log(f"获取公网IP失败: {e}")
        return
    log(f"检测公网IP: {new_ip}")

    # 2 查询DNS解析记录
    try:
        req = models.DescribeRecordListRequest()
        req.Domain = DOMAIN
        resp = client.DescribeRecordList(req)
    except Exception as e:
        log(f"查询DNS记录失败: {e}")
        return

    record = None
    for r in resp.RecordList:
        if r.Name == SUBDOMAIN and r.Type == RECORD_TYPE:
            record = r
            break

    if record is None:
        log(f"未找到解析记录 {SUBDOMAIN}.{DOMAIN} {RECORD_TYPE}")
        return

    log(f"DNS当前记录IP: {record.Value}")

    # 3 IP相同直接退出,不同才执行修改
    if record.Value == new_ip:
        log("IP未发生变化,无需更新")
        return

    log(f"IP不一致,准备更新为 {new_ip}")

    # 4 修改解析记录
    try:
        req = models.ModifyRecordRequest()
        req.Domain = DOMAIN
        req.RecordId = record.RecordId
        req.SubDomain = SUBDOMAIN
        req.RecordType = RECORD_TYPE
        req.RecordLine = RECORD_LINE
        req.Value = new_ip

        modify_resp = client.ModifyRecord(req)
        log("DNS记录更新成功")
        log(modify_resp.to_json_string())
    except Exception as e:
        log(f"更新DNS记录失败: {e}")

if __name__ == "__main__":
    main()
  1. 最后设置定时执行 crontab -e 每五分钟执行一次
    */5 * * * * /usr/bin/python3 /home/pi/ddns_tencent_final.py >> /home/pi/ddns.log 2>&1

可参考的文档