TP-Link DDNS停运后,低成本DDNS域名替代方案
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