一、准备工作
- 阿里云域名
- 获取阿里云的accessKeyId和accessSecret(可以在阿里云控制台个人中心直接获取,建议使用RAM角色来进行权限控制,这样的话安全风险较小)
- CentOS 7 服务器,版本:CentOS Linux release 7.7.1908
二、安装所需的Python包
1 2 3 4 5 6 7 8 9 |
# CentOS 7 系统: pip3 install aliyun-python-sdk-core-v3==2.13.10 pip3 install aliyun-python-sdk-domain pip3 install aliyun-python-sdk-alidns pip3 install requests pip3 install apscheduler # 在系统下先执行 openssl version 查看ssl版本,如是低于1.1.1版本者需要安装指定ssl版本 # 安装指定版本的 urllib3 库,请确保指定的版本与您当前的环境和其他依赖项兼容 pip3 install urllib3==1.25.10 |
1 |
镜像:ddns-aliyun |
三、阿里云ddns动态域名解析代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
import json import sys import os import requests import logging from apscheduler.schedulers.blocking import BlockingScheduler from aliyunsdkcore.client import AcsClient from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest from aliyunsdkalidns.request.v20150109.DeleteSubDomainRecordsRequest import DeleteSubDomainRecordsRequest class Dnscontroller: def __init__(self, access_key_id, access_key_secret, region): """ 初始化 AcsClient Args: access_key_id (str): 阿里云访问密钥 ID access_key_secret (str): 阿里云访问密钥 密钥 region (str): 设置区域, 默认cn-shenzhen """ self.client = AcsClient(access_key_id, access_key_secret, region) # 获取当前脚本文件所在的目录路径 self.current_dir = os.path.dirname(os.path.abspath(sys.argv[0])) def log(self): """日志模块""" log_filename = os.path.join(self.current_dir, "alyddns.log") # 配置日志输出格式 log_format = '%(asctime)s - %(levelname)s - %(lineno)d : %(message)s' logging.basicConfig(level=logging.INFO, format=log_format, filename=log_filename, encoding='utf-8') logger = logging.getLogger(__name__) return logger def add(self, DomainName, RR, Type, Value): """ 添加新的域名解析记录 Args: set_DomainName: 传入域名 set_RR: 传入主机记录 set_Type: 传入记录类型 set_Value: 传入记录值 """ request = AddDomainRecordRequest() request.set_accept_format('json') request.set_DomainName(DomainName) request.set_RR(RR) request.set_Type(Type) request.set_Value(Value) response = self.client.do_action_with_exception(request) return json.loads(response) def update(self, RecordId, RR, Type, Value): """ 修改指定子域名解析记录 Args: set_RecordId: 传入指定子域名解析的RecordId set_RR: 传入主机记录 set_Type: 传入记录类型 set_Value: 传入记录值 """ request = UpdateDomainRecordRequest() request.set_accept_format('json') request.set_RecordId(RecordId) request.set_RR(RR) request.set_Type(Type) request.set_Value(Value) response = self.client.do_action_with_exception(request) return json.loads(response) def delete(self, DomainName, RR): """ 删除指定子域名所有解析记录 Args: set_DomainName: 传入域名 set_RR: 传入主机记录 """ request = DeleteSubDomainRecordsRequest() request.set_accept_format('json') request.set_DomainName(DomainName) request.set_RR(RR) response = self.client.do_action_with_exception(request) return json.loads(response) def get_domain_res_record(self, host_record, domain_name): """ 获取指定子域名解析记录 Args: set_SubDomain: 传入主机记录.域名, 例如blog.csdn.net API请求就会针对子域名blog.csdn.net进行操作, 获取该子域名的解析记录 """ request = DescribeSubDomainRecordsRequest() request.set_accept_format('json') request.set_SubDomain(host_record + "." + domain_name) response = self.client.do_action_with_exception(request) return json.loads(response) def domain_name_analysis(self, mode, domain_name, host_record, record_type): try: # 获取当前子域名的所有解析列表 domain_list = self.get_domain_res_record(host_record, domain_name) if mode == "ipv4": if record_type == "A": # 获取IPv4,该地址可能会失效,如失效者更换新地址 ipv4 = requests.get('https://ifconfig.me/ip').text print(f"获取到IPv4地址: {ipv4}") if domain_list['TotalCount'] == 0: self.add(domain_name, host_record, record_type, ipv4) print("新建域名解析成功") elif domain_list['TotalCount'] == 1: if domain_list['DomainRecords']['Record'][0]['Value'] != ipv4: self.update(domain_list["DomainRecords"]["Record"][0]["RecordId"], host_record, record_type, ipv4) print("修改域名解析成功—update") else: print("IPv4地址没变") else: self.delete(domain_name, host_record) self.add(domain_name, host_record, record_type, ipv4) print("修改域名解析成功—delete") else: self.log().error("record_type记录类型(ipv4)填写不正确, 必须是: A") sys.exit() elif mode == "ipv6": if record_type == "AAAA": # 获取IPv6,该地址可能会失效,如失效者更换新地址 ipv6 = requests.get("https://6.ipw.cn/api/ip/myip?json").text get_ipv6 = json.loads(ipv6)["IP"] print(f"获取到IPv6地址: {get_ipv6}") if domain_list['TotalCount'] == 0: self.add(domain_name, host_record, record_type, get_ipv6) print("新建IPV6域名解析成功") elif domain_list['TotalCount'] == 1: if domain_list['DomainRecords']['Record'][0]['Value'] != get_ipv6: self.update(domain_list["DomainRecords"]["Record"][0]["RecordId"], host_record, record_type, get_ipv6) print("修改IPV6域名解析成功—update") else: print("IPV6地址没变") else: self.delete(domain_name, host_record) self.add(domain_name, host_record, record_type, get_ipv6) print("修改IPV6域名解析成功—delete") else: self.log().error("record_type记录类型(ipv6)填写不正确, 必须是: AAAA") sys.exit() else: self.log().error("mode类型填写不正确, 必须是: ipv4 & ipv6") sys.exit() except Exception as i: self.log().error(i) sys.exit() if __name__ == "__main__": def execute(): run = Dnscontroller("AccessKey ID", "AccessKey Secret", "cn-shanghai") run.domain_name_analysis("类型(ipv4 & ipv6)", "域名", "主机记录", "记录类型(A & AAAA)") # 先执行一次任务 execute() # BlockingScheduler调度器,适用于小型应用程序或简单任务调度的场景 scheduler = BlockingScheduler(timezone='Asia/Shanghai') # 按间隔一定时间执行任务:seconds=秒;minutes=分钟;hours=小时 scheduler.add_job(execute, 'interval', minutes=10) scheduler.start() |
1 2 3 4 |
此脚本运行后,默认定时任务为10分支触发一次 其他检测地址收集: http://ipv4.icanhazip.com |
四、CentOS 7 设置开机自动运行脚本
1.把alyddns.py文件上传到服务器“/home”目录下,并赋予权限
1 2 |
cd /home chmod +x alyddns.py |
.脚本添加到systemd服务管理器中
1 |
vi /etc/systemd/system/alyddns.service |
1 2 3 4 5 6 7 8 9 10 |
[Unit] Description=aly DDNS After=network.target network-online.target systemd-networkd-wait-online.service [Service] ExecStart=/usr/bin/python3 /home/alyddns.py WorkingDirectory=/home/ [Install] WantedBy=multi-user.target |
1 2 3 4 5 6 7 8 |
# Description:描述该服务的文本,可以随意命名,用于标识该服务的目的 # After:定义所依赖的其他系统单元(units)实例中表示: # network.target表示基本的网络服务已启动完成 # network-online.target表示网络连接已准备就绪 # systemd-networkd-wait-online.service确保网络连接建立后继续启动 # ExecStart: 指定要执行的命令或脚本(/usr/bin/python3程序路径,根据实际情况替换。/home/alyddns.py脚本路径) # WorkingDirectory: 指定服务的工作目录 # WantedBy: 指定服务所属的运行级别。在CentOS 7中,multi-user.target表示该服务将在多用户模式下启动 |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#保存并关闭文件,重新加载systemd配置 systemctl daemon-reload # ④启用服务以在开机时自动运行 systemctl enable alyddns.service # ⑤启动服务,使其立即生效 systemctl start alyddns.service # 停止服务 systemctl stop alyddns.service # 查看服务状态 systemctl status alyddns.service |
1 2 3 |
参考文档: https://developer.aliyun.com/article/702552 https://blog.csdn.net/qq_45664055/article/details/125600345 |
- 本文固定链接: https://www.yoyoask.com/?p=6642
- 转载请注明: shooter 于 SHOOTER 发表