TP-Link DDNS停运后,低成本DDNS域名替代方案

TP-Link官方通知

因业务调整,TPDDNS服务于2025年6月30日正式停止*.tpddns.cn的域名解析服务。

TP官方给出替代解决方案

花生壳 最低19元/年科迈 最低98元/年3322 最低168元/年

阿里云域名自主实现动态解析

1. 购买阿里云域名

注意这个方案是基于阿里云的,别的地方买的域名要怎么解析我可不知道啊。

当然你想要一个好的域名可以自己看着购买,我买了一个8块的.homes域名,正好机器是放在家里的,和域名也和配。

信息备案

在购买前还需要进行一个信息备案,这里使用个人的,如果你是企业的话,需要使用企业的信息备案,相对麻烦一点。

备案审核需要一些时间一般来讲半小时后看就可以了。完成后是这个样子

接下来就可以支付购买域名了,购买完域名需要进行审核和备案,所以在等个1小时左右就可以解析了,这期间可以做以下事情。

生成aliyun开放接口的AccessKey

从下方图入口进入open api密钥设置页面 进入后如果你已经有key了并且还记得你的密钥是多少那后续直接使用就好,如果没有或忘记了创建一个新的。

自己实现DDNS解析

自己构建或者克隆我放在GitHub上的项目,项目很简单

克隆项目

git clone https://github.com/195144146/aliyun-ddns#

构建镜像

# 切换到项目路径下

cd aliyun-ddns

docker build --network=host -t aliyun-ddns .

创建启动容器 ALIBABA_CLOUD_ACCESS_KEY_ID = 阿里云上的ACCESS_KEY ALIBABA_CLOUD_ACCESS_KEY_SECRET = ACCESS_KEY对应的SECRET DOMAIN_NAME = 你购买的域名

docker run -d --restart always --name aliyunDDNS -e PYTHONUNBUFFERED=1 -e ALIBABA_CLOUD_ACCESS_KEY_ID=xxx -e ALIBABA_CLOUD_ACCESS_KEY_SECRET=xxx -e DOMAIN_NAME=xxx aliyun-ddns

如果你有这台机器有科学上网的话,请绕过以下域名

alidns.cn-hangzhou.aliyuncs.comifconfig.mehttpbin.orgipinfo.io

说明

代码很简单,有什么问题可以提issue,作者会不定期解决,或者自己修改一下。不建议修改代码中线程睡眠时长到太低值,可能会被服务器禁掉。

补充说明

为了方便无法访问github的读者,主要代码如下及其构件环境如下

Python=3.10.18 依赖

alibabacloud_alidns20150109=3.5.9

主题结构 -main.py -Dockerfile -environment.tml

代码

main.py

import os

import time

import requests

from alibabacloud_alidns20150109.client import Client as Alidns20150109Client

from alibabacloud_alidns20150109.models import DescribeDomainRecordsResponse, UpdateDomainRecordResponse

from alibabacloud_credentials.client import Client as CredentialClient

from alibabacloud_tea_openapi import models as open_api_models

from alibabacloud_alidns20150109 import models as alidns_20150109_models

from alibabacloud_tea_util import models as util_models

from alibabacloud_tea_util.client import Client as UtilClient

def create_client() -> Alidns20150109Client:

"""

使用凭据初始化账号Client

@return: Client

@throws Exception

"""

# 工程代码建议使用更安全的无AK方式,凭据配置方式请参见:https://help.aliyun.com/document_detail/378659.html。

credential = CredentialClient()

config = open_api_models.Config(

credential=credential

)

# Endpoint 请参考 https://api.aliyun.com/product/Alidns

config.endpoint = f'alidns.cn-hangzhou.aliyuncs.com'

return Alidns20150109Client(config)

def describe_domain_records(domain_name: str):

"""

查询解析记录

:return:

"""

client = create_client()

describe_domain_records_request = alidns_20150109_models.DescribeDomainRecordsRequest()

# 设置请求参数

describe_domain_records_request.domain_name = domain_name

runtime = util_models.RuntimeOptions()

try:

response: DescribeDomainRecordsResponse = client.describe_domain_records_with_options(describe_domain_records_request, runtime)

if response.status_code == 200:

# 打印查询结果

return response.body.domain_records.record

else:

raise Exception("查询解析记录失败")

except Exception as error:

# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。

# 错误 message

print(error.message)

# 诊断地址

print(error.data.get("Recommend"))

UtilClient.assert_as_string(error.message)

def add_domain_record(domain_name: str, ip_addr: str):

"""

新增解析记录

:param domain_name: 域名

:param ip_addr: 公网IP地址

:return:

"""

client = create_client()

add_domain_record_request = alidns_20150109_models.AddDomainRecordRequest()

# 设置请求参数

add_domain_record_request.domain_name = domain_name

add_domain_record_request.rr = '@'

add_domain_record_request.type = 'A'

add_domain_record_request.value = ip_addr

runtime = util_models.RuntimeOptions()

try:

client.add_domain_record_with_options(add_domain_record_request, runtime)

except Exception as error:

# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。

# 错误 message

print(error.message)

# 诊断地址

print(error.data.get("Recommend"))

UtilClient.assert_as_string(error.message)

def update_domain_record(record_id: str, ip_addr: str):

"""

更新解析记录

:param domain_name: 域名

:param ip_addr: 公网IP地址

:return:

"""

client = create_client()

update_domain_record_request = alidns_20150109_models.UpdateDomainRecordRequest()

# 设置请求参数

update_domain_record_request.record_id = record_id

update_domain_record_request.rr = '@'

update_domain_record_request.type = 'A'

update_domain_record_request.value = ip_addr

runtime = util_models.RuntimeOptions()

try:

response: UpdateDomainRecordResponse = client.update_domain_record_with_options(update_domain_record_request, runtime)

if response.status_code == 200:

return True

except Exception as error:

# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。

# 错误 message

print(error)

# 诊断地址

print(error.data.get("Recommend"))

UtilClient.assert_as_string(error.message)

return False

def get_public_ip() -> str:

"""

获取公网IP

:return:

"""

try:

response = requests.get("http://ifconfig.me/ip", timeout=20)

if response.status_code == 200:

return response.text

except Exception as error:

print(error)

try:

response = requests.get('https://httpbin.org/ip', timeout=20)

if response.status_code == 200:

return response.json()['origin']

except Exception as error:

print(error)

try:

response = requests.get('https://ipinfo.io/json', timeout=20)

if response.status_code == 200:

return response.json()['ip']

except Exception as error:

print(error)

return get_public_ip()

if __name__ == '__main__':

# 获取环境变量中的域名

domain_name = os.getenv("DOMAIN_NAME")

# 从ifconfig.me获取公网IP

ip_addr = get_public_ip()

print(f"获取到当前公网IP地址: {ip_addr}")

domain_records = describe_domain_records(domain_name)

if len(domain_records) == 0:

add_domain_record(domain_name, ip_addr)

domain_records = describe_domain_records(domain_name)

record_id = domain_records[0].record_id

old_addr = domain_records[0].value

print(f"获取到当前解析记录公网ip地址: {old_addr}")

if ip_addr != old_addr:

success = update_domain_record(record_id, ip_addr)

if success:

print("解析记录更新成功")

domain_records = describe_domain_records(domain_name)

old_addr = domain_records[0].value

print(f"获取到当前解析记录公网ip地址: {old_addr}")

# 每30秒检查一次ip是否变化

while True:

time.sleep(30)

try:

ip_addr = get_public_ip()

print(f"获取到当前公网IP地址: {ip_addr}")

if ip_addr != old_addr:

success = update_domain_record(record_id, ip_addr)

if success:

print("解析记录更新成功")

domain_records = describe_domain_records(domain_name)

old_addr = domain_records[0].value

print(f"获取到当前解析记录公网ip地址: {old_addr}")

except Exception as error:

print(error)

Dockerfile

FROM continuumio/miniconda3:25.3.1-1

LABEL authors="yujiajun"

WORKDIR /app

COPY environment.yml .

COPY main.py .

RUN conda env create --prefix ./venv -f environment.yml

CMD ["conda", "run", "--no-capture-output", "--prefix", "./venv", "python", "main.py"]

environment.yml

name: AliyunDDns

channels:

- defaults

dependencies:

- python=3.10.18

- pip:

- alibabacloud_alidns20150109==3.5.9