群晖DDNS解析

article/2025/10/6 19:11:26

网上关于DDNS解析的介绍已经很多了,我这里主要列举通过阿里云和Cloudflare进行解析。使用两个解析的原因是阿里云的域名必须要备案,不然会被阿里云封掉(阿里云解析的域名如果解析的IP不是阿里云服务器的,还会提示要求使用阿里云服务器。)。而Cloudflare不用备案,可以直接用。在阿里云申请的域名可以在阿里云上配置为通过Cloudflare解析。当然不只Cloudflare,其实有很多提供DNS解析服务的厂商都提供了DNS的API,就不一一列举了。
在这里插入图片描述
如果买的群晖服务器的话,本身群晖会送一个域名,也会自动做DDNS解析,不需要自己折腾。如果没有群晖的服务器或者想用自己的已经申请的域名,就需要自己做DDNS解析。DDNS解析说白了就是调用第三方提供的更新DNS的API。
步骤如下:

  1. 获取当前的公网IP;
  2. 对比当前公网IP是否变化;
  3. 若发生变化则更新DNS解析。

下面是具体实现过程,我通过python来实现。

1.获取当前的公网IP

获取公网ip目前我有四种方式:

  1. 通过www.ifconfig.me获取,因为群晖本身也是linux环境,代码跑在群晖上,可以直接curl www.ifconfig.me -s得到公网ip。不过这个网站好像是国外的,有时候访问很慢,可能会获取超时,这时候可以尝试其他方式。
  2. 通过200019.ip138.com获取,这是国内的获取ip,百度上搜ip就是调用的这个网站的。优点速度快,缺点要自己分析页面提取ip。
  3. 自己搭一个nginx服务器,然后配置nginx获取真实IP。优点不会受制于别人,获取方便。缺点是有个服务器,要自己部署个程序。
  4. 自己写代码解析获取真实IP,这个我没试过,理论上也是可以的,不然nginx怎么能拿到的?

nginx获取公网ip,配置如下:

   server {listen       80;server_name  localhost;location / {default_type text/html;return 200 "$remote_addr";}}

可以测试下: curl http://localhost

下面的代码中实现了前两种方式,其实我也实现了第三种方式,但我自己的域名安全起见,不方便公开,代码就不公布了,其实也简单,就是一个request发送get请求就好了。

# -*- coding:UTF-8 -*-
import re
import subprocessimport requestsfrom util.tonggu_logger import TongguLoggerlogger = TongguLogger().getLogger()"""get network ip@version: python3.x@author: wangjf@software: PyCharm@file: collect.py@time: 2019/7/8 19:30
"""
def get_network_ip():ip = getIpFromIfConfig()if ip is None:ip = getIpFromIp138()if len(ip) == 0:return None# extract ipresult = re.findall(r"\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b", ip)if result:return result[0]return None"""get ip from www.ifconfig.me@version: python3.x@author: wangjf@software: PyCharm@file: collect.py@time: 2019/7/8 19:30
"""
def getIpFromIfConfig():try:logger.info("start get ip from www.ifconfig.me")rows = subprocess.getoutput('curl www.ifconfig.me -s')if rows:logger.info("get ip %s" % rows)ip = rowselse:raise Exception('get ip from www.ifconfig.me failed')return ipexcept Exception:logger.error("get ip from www.ifconfig.me failed", exc_info=True)return None"""get ip from ip138.com@version: python3.x@author: wangjf@software: PyCharm@file: collect.py@time: 2019/7/8 19:35
"""
def getIpFromIp138():try:logger.info("start get ip from 200019.ip138.com")headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'}html = requests.get('http://200019.ip138.com/', headers=headers)rows = re.findall('<p align="center">(.*?)</p>', html.text, re.S)if rows:logger.info("get ip %s" % rows)ip = rows[0]else:raise Exception('get ip from 200019.ip138.com failed')return ipexcept Exception:logger.error("get ip from 200019.ip138.com failed", exc_info=True)return None

2.对比当前公网IP是否变化

这个步骤其实比较简单,把获取的对公ip存在本地文件,然后下次获取对公ip的时候判断新获取的ip与文件中的ip是否一致,不一致则修改。
下面的代码中包含了获取对公ip、判断ip是否变化以及更新dns。若用的阿里云,则修改ali这段,若用的cloudflare则修改flare这段。

# -*- coding:UTF-8 -*-
from ddns.collect import get_network_ip
from ddns.alicloud import AliCloudDns
from ddns.cloudflare import CloudflareDnsimport sys
from util.tonggu_logger import TongguLogger
import util.path
import pathliblogger = TongguLogger().getLogger()ali = {"access_key_id": "xxx","access_secret": "xxx","region_id": "cn-hangzhou","domain": "xxx.com","domain-a": "home"
}flare = {"access_key_id": "xxx@163.com","access_secret": "xxx","region_id": "xxx","domain": "xxx.com","domain-a": "home"
}# save content and return true if changed, otherwise return false
def save_content(path, filename, content):path = pathlib.Path(str)if not path.exists():path.mkdir()file = pathlib.Path(path + '/' + filename)if file.exists():with file.open() as f:str = f.readline()if content == str:return False# write filewith file.open('w') as f:f.writelines(content)return Trueif __name__ == "__main__":try:network_ip = get_network_ip()if network_ip is None:raise Exception("get ip failed")# check ip is changedif save_content('/tmp', 'ip', network_ip) == False:sys.exit(2)except Exception:logger.error("get ip failed", exc_info=True)sys.exit(2)# update dnstry:# update alicloudlogger.info("updata aliyun dns")aliCloudDns = AliCloudDns(ali["access_key_id"], ali["access_secret"], ali["region_id"])record = aliCloudDns.DescribeDomainRecords(ali["domain"], ali["domain-a"])aliCloudDns.UpdateDomainRecord(record, network_ip)logger.info('update aliyun dns success')except Exception:logger.error("update aliyunv dns failed", exc_info=True)try:# update cloudflarelogger.info("updata cloudflare dns")dns = CloudflareDns(flare["access_key_id"], flare["access_secret"], flare["region_id"])record = dns.DescribeDomainRecords(ali["domain"], ali["domain-a"])dns.UpdateDomainRecord(record, network_ip)logger.info('update  cloudflare dns success')except Exception:logger.error("update cloudflare dns failed", exc_info=True)

3.更新DNS

阿里云DNS更新代码,两个函数,第一个函数用于获取之前设置的DNS解析记录(主要拿到这条数据的id),第二个函数用于更新DNS。

# -*- coding:UTF-8 -*-
import jsonfrom aliyunsdkalidns.request.v20150109.DescribeDomainRecordsRequest import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109.UpdateDomainRecordRequest import UpdateDomainRecordRequest
from aliyunsdkcore.client import AcsClientclass AliCloudDns:def __init__(self, access_key_id, access_secret, region_id):self._client_ = AcsClient(access_key_id, access_secret, region_id)"""search Records@:param main_domain @:param child_domain@version: python3.x@author: wangjf@software: PyCharm@file: alicloud.py@time: 2019/7/8 20:40"""def DescribeDomainRecords(self, main_domain, child_domain):request = DescribeDomainRecordsRequest()request.set_accept_format('json')request.set_DomainName(main_domain)response = self._client_.do_action_with_exception(request)result = json.loads(str(response, encoding='utf-8'))for record in result["DomainRecords"]["Record"]:if record["RR"] == child_domain:return record"""update record by id@:param record @:param ip @version: python3.x@author: wangjf@software: PyCharm@file: alicloud.py@time: 2019/7/8 20:40"""def UpdateDomainRecord(self, record, ip):# not need to update if not changeif record['Value'] == ip:return ''request = UpdateDomainRecordRequest()request.set_accept_format('json')request.set_RecordId(record['RecordId'])request.set_RR(record['RR'])request.set_Type(record['Type'])request.set_Value(ip)response = self._client_.do_action_with_exception(request)return str(response, encoding='utf-8')

cloudflare的DNS更新代码,也是两个函数跟阿里云类似。

# -*- coding:UTF-8 -*-
import requestsimport jsonclass CloudflareDns:def __init__(self, access_key_id, access_secret, zone_id):self.__access_key_id = access_key_idself.__access_secret = access_secretself.__zone_id = zone_id"""search Records@:param main_domain @:param child_domain@version: python3.x@author: wangjf@software: PyCharm@file: coludflare.py@time: 2020/2/8 21:40"""def DescribeDomainRecords(self, main_domain, child_domain):url = "https://api.cloudflare.com/client/v4/zones/%s/dns_records?type=A&name=%s.%s" % (self.__zone_id, child_domain, main_domain)headers = {"X-Auth-Email": self.__access_key_id, "X-Auth-Key": self.__access_secret,"Content-Type": "application/json"}response = requests.get(url, headers=headers).textresult = json.loads(response)return result["result"][0]"""update record by id@:param record @:param ip @version: python3.x@author: wangjf@software: PyCharm@file: coludflare.py@time: 2020/2/8 21:40"""def UpdateDomainRecord(self, record, ip):# not need to update if not changeif record['content'] == ip:return ''url = "https://api.cloudflare.com/client/v4/zones/%s/dns_records/%s" % (self.__zone_id, record['id'])headers = {"X-Auth-Email": self.__access_key_id, "X-Auth-Key": self.__access_secret,"Content-Type": "application/json"}data = {"type": "A", "name": record['name'], "content": ip, "ttl": 600, "proxied": False}response = requests.put(url, json=data, headers=headers)return response.text

获取完整代码

注意:修改exec_ddns.py中的ali和flare,配置对应的密钥或者登陆名密码。如果只使用其中一个,可以把另一个删掉,对应删掉代码。

下面是获取阿里云的AccessKey,在右上角,剩余步骤都是傻瓜式的,不介绍了。
ali = {
“access_key_id”: “xxx”, # AccessKey
“access_secret”: “xxx”, # AccessSecret
“region_id”: “cn-hangzhou”, # 区域(默认就好)
“domain”: “xxx.com”, # 你的域名
“domain-a”: “home” # 你的域名前缀,比如www.baidu.com其中的www
}
在这里插入图片描述
下面是cloudflare配置APIToken
flare = {
“access_key_id”: “xxx@163.com”, # cloudflare登陆邮箱
“access_secret”: “xxx”, # cloudflare登陆密码
“region_id”: “xxx”, # 下面申请的api token
“domain”: “xxx.com”, # 你的域名
“domain-a”: “home” # 你的域名前缀,比如www.baidu.com其中的www
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

把代码拷贝到群晖服务器上,设置任务计划

我配置的每5分钟跑一次
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


http://chatgpt.dhexx.cn/article/nVpbXa1u.shtml

相关文章

群晖折腾记1—群晖NAS使用docker中的ddns-go,DDNS阿里云ali实现Ipv6访问

群晖折腾记1—群晖NAS使用docker中的ddns-go,DDNS阿里云ali实现Ipv6访问 前置条件科普时间具体步骤1. 域名购买2. 获取AccessKey ID和Secret3. 获取免费SSL证书4. 在docker中运行ddns-go6.设置反向代理 前置条件 1、移动宽带只有IPv6公网地址&#xff0c;若你的宽带为电信或联…

群晖-第1章-IPV6的DDNS

群晖-第1章-IPV6的DDNS 方案&#xff1a;腾讯云群晖DS920 本文参考群晖ipv6 DDNS-go教程-牧野狂歌&#xff0c;感谢原作者的分享。 这篇文章只记录了我需要的部分&#xff0c;其他的可以查看原文&#xff0c;原文还记录了更多的内容&#xff0c;可能帮到你。 一、购买域名 …

群晖docker实现阿里云动态公网域名解析ddns服务

日常生活中&#xff0c;一般家庭用户宽带使用的都是内网ip&#xff0c;如果需要在外网就是远程使用&#xff0c;需要将家庭ip向电信部门申请变更为公网ip&#xff0c;通常情况下&#xff0c;我们获得的都是动态公网ip&#xff0c;这种ip每隔一段时间都会自动变化&#xff0c;这…

手把手教你在群晖中设置阿里云DDNS

由于运营商提供的公网ip是动态的&#xff0c;所以需要设置ddns实时地更新域名服务商处的绑定到我们域名上的ip地址。 1、在阿里云购买一个域名&#xff08;如何购买不做展示&#xff09; 2、群晖中安装docker 在群晖的套件中心中安装docker 安装完毕后&#xff0c;打开docke…

串口通信RXTXcomm使用

准备工作 1.下载 地址&#xff1a; http://fizzed.com/oss/rxtx-for-java 这里的下载是根据jdk安装的位数下载&#xff0c;我之前下载的是W64的版本&#xff0c;电脑系统也是64的&#xff0c;但是代码跑不起来&#xff0c;后来才发现我电脑的JDK是32位的。 2、 下载完成后将 …

Java实现串口通信

串口通信原理 串口通信&#xff08;Serial Communications&#xff09;的概念非常简单&#xff0c;串口按位&#xff08;bit&#xff09;发送和接收字节。 尽管比按字节&#xff08;byte&#xff09;的并行通信慢&#xff0c;但是串口可以在使用一根线发送数据的同时用另一根线…

使用RXTXcomm进行串口通信

RXTXcomm 串口通信 虚拟串口和串口调试助手的使用 虚拟串口软件&#xff1a;VSPD&#xff0c;https://www.eltima.com/cn/products/vspdxp/ VSPD会自动识别出本台计算上有几个物理串口&#xff0c;例如本机只有一个物理串口COM1。在右侧端口管理的分页中&#xff0c;添加虚拟端…

C#实现串口通信解析

1. 串口硬件信号定义 串口通信&#xff08;Serial Communications&#xff09;是指外设和计算机间通过数据信号线、地线等按位&#xff08;bit&#xff09;进行传输数据的一种通信方式&#xff0c;属于串行通信方式&#xff0c;能够实现远距离通信&#xff0c;长度可达1200米。…

10、STM32的串口(UART)及串口通信原理(内附代码)

一、通信接口介绍 1、处理器与外部设备通信的两种方式&#xff1a; 并行通信 - 传输原理&#xff1a;数据各个位同时传输。 -优点&#xff1a;速度快 -缺点&#xff1a;占用引脚资源多 串行通信 - 传输原理&#xff1a;数据按位顺序传输&#xff0…

串口通信的概念与实现

uart串口通信概念数据结构termios作用与设置串口读写实现 UART串口通信概念 通用异步收发传输器&#xff08;Universal Asynchronous Receiver/Transmitter)&#xff0c;通常称作uart&#xff0c;是一种异步收发传输器&#xff0c;uart作为异步串口通信协议的一种&#xff0c;…

java基于RXTXcomm的串口程序

准备工作 首先下载官方提供的jar包和.dll文件&#xff0c;dll文件有两个&#xff0c;一个是rxtxSerial&#xff0c;一个是rxtxParallel&#xff0c;分别表示串口和并口。因为我开发串口&#xff0c;所以把rxtxSerial.dll放到了jdk1.8.0_171/jre/bin和jre1.8.0_171/bin目录下&a…

51单片机串口多机通信的原理与编程实现

51单片机串口多机通信 需要用的的寄存器 (了解的可直接跳到下一节&#xff09; TMOD 定时器/计数器模式控制寄存器TCON 定时器控制寄存器SCON 串口控制寄存器PCON 电源控制位寄存器IE 中断中断使能寄存器 补充说明&#xff0c;TH1 预置值计算&#xff0c;中断源 波特率计算公式…

Java串口通信详解

序言 说到开源&#xff0c;恐怕很少有人不挑大指称赞。学生通过开源代码学到了知识&#xff0c;程序员通过开源类库获得了别人的成功经验及能够按时完成手头的工程&#xff0c;商家通过开源软件赚到了钱……&#xff0c;总之是皆大欢喜。然而开源软件或类库的首要缺点就是大多缺…

Java串口通信(RXTX)

这几天要用到串口通信,而我最会的Java,所以我就去学了一下怎么用Java进行串口通信 用的jar包是RXTX官网:http://rxtx.qbang.org/ 下载地址:http://fizzed.com/oss/rxtx-for-java 下载好Jar包后,首先需要配置,这里我用的Eclipse Window->Preferences->Java->Build …

十一、串口通信的基本原理与应用

通常用&#xff1a;SMOD 0&#xff0c;0xfd 利用51单片机的串行接口与上位机建立传输信道进行数据的收发。采用8位UART模式&#xff0c;即模式1&#xff0c;波特率为9600BPS。数据发送采用查询方式&#xff0c;数据接收采用中断方式。 系统上电初始化之后&#xff0c;单片机向…

【超简单的串口通信的工作原理】

下图是电脑收到单片机经过串口发送的信息&#xff0c; 那么电脑是如何与单片机进行串口通信的呢&#xff1f; 首先&#xff0c;任何一种通信都要包括硬件物理接口和软件通信协议。 串口通信物理接口如下图。单片机通过发送端将数据从左往右一位一位按顺序发送&#xff1b;且在…

串口通信基本原理

目录 串口通信连线&#xff1a; 串口通信时序&#xff1a; 起始位&#xff1a; 数据位&#xff1a; 校验位&#xff1a; 停止位&#xff1a; 总结&#xff1a; 串口通信特点&#xff1a; 基于串口的通讯接口&#xff1a; 串口通信连线&#xff1a; 任何通信都要有信息…

一篇短文让你彻底理解什么是串口通信

1 并行与串行通信 机器的通信方式有两种&#xff0c;分别是并行通信与串行通信。 并行通信&#xff1a;并行通信是指多比特数据同时通过并行线进行传送&#xff0c;这样数据传送速度大大提高&#xff0c;但并行传送的线路长度受到限制&#xff0c;因为长度增加&#xff0c;干…

Java RXTX 实现串口通信

目录 串口&#xff08;通信&#xff09;概述 串口调试助手 RXTX 下载与依赖 Java 开发实战 串口(通信)概述 1、串口通信是指串口按位&#xff08;bit&#xff09;发送和接收字节 2、串口通信可以在使用一根线发送数据的同时用另一根线接收数据 3、串口通信常用的协议包括…

串口通信原理

并行通信是指数据的各个位用多条数据线同时进行传输 优点&#xff1a;传输速度快 缺点&#xff1a;占用引脚资源多 串行通信是将数据分成一位一位的形式在一条传输线上逐个传输 优点&#xff1a;通信线路简单、占用引脚资源少 缺点&#xff1a;传输速度慢 同步通信&#xf…