家庭服务器或NAS建立完成后,需要外网访问,但是IPv4比较难申请,不过IPv6大部分地区已经普及,故选择IPv6来做DDNS。
本文,使用的是阿里域名解析,以及Ubuntu系统,方法如下。
- 首先需要申请对应的key和密钥,建议创建个子用户,仅有修改DNS的权限,如下:

2. 创建完密钥后,安装依赖的库:
# 使用 pip 命令,安装阿里云DNS相关的库: $ pip install aliyun-python-sdk-alidns aliyun-python-sdk-core aliyun-python-sdk-core-v3 aliyun-python-sdk-domain
3. 创建 aliddns.py 文件,我的脚本里会同步修改本地的一些配置文件,请根据实际情况,选择是否屏蔽;以下是我的脚本:
from aliyunsdkcore.client import AcsClient from aliyunsdkcore.acs_exception.exceptions import ClientException from aliyunsdkcore.acs_exception.exceptions import ServerException from aliyunsdkalidns.request.v20150109.DescribeSubDomainRecordsRequest import DescribeSubDomainRecordsRequest from aliyunsdkalidns.request.v20150109.DescribeDomainRecordsRequest import DescribeDomainRecordsRequest import requests from urllib.request import urlopen import json import sys from netaddr.ip import IPNetwork, IPAddress import subprocess # ---------------------------- key 密钥 域名 ------------------------------------------ accessKeyId = "TODO 改成自己的accessKeyId" accessSecret = "TODO 改成自己的accessSecret" domain = "qiangubafang.demo" #TODO 你的主域名 name_ipv6 = "subdomain" #TODO 要进行ipv6 ddns解析的子域名 client = AcsClient(accessKeyId, accessSecret, 'cn-hangzhou') def update(RecordId, RR, Type, Value): # 修改域名解析记录 from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest request = UpdateDomainRecordRequest() request.set_accept_format('json') request.set_RecordId(RecordId) request.set_RR(RR) request.set_Type(Type) request.set_Value(Value) response = client.do_action_with_exception(request) def add(DomainName, RR, Type, Value): # 添加新的域名解析记录 from aliyunsdkalidns.request.v20150109.AddDomainRecordRequest import AddDomainRecordRequest request = AddDomainRecordRequest() request.set_accept_format('json') request.set_DomainName(DomainName) request.set_RR(RR) # https://blog.zeruns.tech request.set_Type(Type) request.set_Value(Value) response = client.do_action_with_exception(request) print("自动修改阿里域名地址") request = DescribeSubDomainRecordsRequest() request.set_accept_format('json') request.set_DomainName(domain) request.set_SubDomain(name_ipv6 + '.' + domain) request.set_Type("AAAA") response = client.do_action_with_exception(request) # 获取域名解析记录列表 domain_list = json.loads(response) # 将返回的JSON数据转化为Python能识别的 ip = urlopen('https://api-ipv6.ip.sb/ip').read() # 使用IP.SB的接口获取ipv6地址 ipv6 = str(ip, encoding='utf-8') print("获取到IPv6地址:%s" % ipv6) if len(sys.argv) == 2 : ipv6 = sys.argv[1] print("手动设置IP: %s" % sys.argv[1]) if domain_list['TotalCount'] == 0: add(domain, name_ipv6, "AAAA", ipv6) print("新建域名解析成功") elif domain_list['TotalCount'] == 1: dnsIPv6Addr = domain_list['DomainRecords']['Record'][0]['Value'].strip() dnsIPv6Prefix = str(IPNetwork(dnsIPv6Addr + "/64").network) curIPv6Prefix = str(IPNetwork(ipv6.strip() + "/64").network) curIPv6Addr = curIPv6Prefix + "100" #TODO 改为末尾为100的固定IP;如不需要固定可注释掉该行 print("IPv6 DNS地址为 : %s " % dnsIPv6Addr) print("IPv6 当前地址为 : %s " % curIPv6Addr) if dnsIPv6Addr != curIPv6Addr: update(domain_list['DomainRecords']['Record'][0]['RecordId'], name_ipv6, "AAAA", curIPv6Addr) print("IPv6 修改域名解析成功,新IP为 %s" % curIPv6Addr) print("-----------------注意:更新域名成功后,这里会修改本地配置,如不需要可注释掉-----------------------------") print("修改IPv6配置文件(bind9, netplan, iptables, isc-dhcp-server):"); cmdChangeIPv6Prefix = subprocess.getoutput("/home/my_cron.sh/chip6_prefix.sh " + dnsIPv6Prefix + " " + curIPv6Prefix + " yes") print(' 输出: ', cmdChangeIPv6Prefix); print("--------------------------------------------------------------------------------------") else: print("IPv6 地址相同 : 不做修改") elif domain_list['TotalCount'] > 1: print("多个相同子域名,不做修改")
我需要修改bind9,netplan,iptables防火墙的配置文件,调用时需要root权限,我的chip6_prefix.sh脚本如下:
$ cat chip6_prefix.sh #!/bin/bash old_ip=$1 new_ip=$2 if [ ! -n "$1" ] ;then echo "参数1为空, 用法-> [命令 旧IP前缀 新IP前缀 仅模拟/执行修改]"; exit; fi if [ ! -n "$2" ]; then echo "参数2为空, 用法-> [命令 旧IP前缀 新IP前缀 仅模拟/执行修改]"; exit; fi if [[ $3 != "yes" ]]; then echo "test change file."; echo "s/$old_ip/$new_ip/gi"; sed "s/$old_ip/$new_ip/gi" /home/ip-firewall/run.sh; sed "s/$old_ip/$new_ip/gi" /etc/bind/db.yun.rangotec.com; sed "s/$old_ip/$new_ip/gi" /etc/dhcp/dhcpd6.conf; sed "s/$old_ip/$new_ip/gi" /etc/netplan/00-installer-config.yaml; old_ip_arpa=arpaname ${old_ip}100
; new_ip_arpa=arpaname ${new_ip}100
; echo "s/$old_ip_arpa/$new_ip_arpa/gi"; sed "s/$old_ip_arpa/$new_ip_arpa/gi" /etc/bind/named.conf.local; echo "simulation finished"; else echo "do change file!!!!"; echo "s/$old_ip/$new_ip/gi"; sed -i "s/$old_ip/$new_ip/gi" /home/ip-firewall/run.sh; sed -i "s/$old_ip/$new_ip/gi" /etc/bind/db.yun.rangotec.com; sed -i "s/$old_ip/$new_ip/gi" /etc/dhcp/dhcpd6.conf; sed -i "s/$old_ip/$new_ip/gi" /etc/netplan/00-installer-config.yaml; old_ip_arpa=arpaname ${old_ip}100
; new_ip_arpa=arpaname ${new_ip}100
; echo "s/$old_ip_arpa/$new_ip_arpa/gi"; sed -i "s/$old_ip_arpa/$new_ip_arpa/gi" /etc/bind/named.conf.local; echo "process finished"; echo "----->restart service" systemctl reload bind9 systemctl restart isc-dhcp-server systemctl restart ip_firewall netplan apply echo "<<<<<<restart service finished" fi
单独调用方法为:
chip6_prefix.sh 旧IP前缀 新IP前缀 yes # 传入yes为真实修改,否则仅模拟
5. 如有必要,把aliddns.py 添加到 /tec/cron.d/crontab脚本里,定时检查,一旦不一致,自动更新。如每5分钟检查一次:
# 每几分钟检查下IPv6是否发生变化 */5 * * * * root python3 /home/my_cron.sh/aliddns.py >> /var/log/my_cron.log 2>&1 &
文章评论