引
一直想利用树莓派亲手搭建几种服务器来加深了解,奈何电信光猫每次重启后都会重新分配公网IP。
只能先想办法解决这个最基本的问题,起初的时候没想到该怎么搞。当时手里有一个便宜买的海外虚拟主机,打算让树莓派每次开机后自动发送自己的IP到那个主机上,然后我需要外网访问的时候,从海外主机获取到ip然后在访问。。。。。后来想了想我图个啥。 最后从网络上找了这种通过阿里API去动态解析IP的方式,不过网上找到的虽然思路基本相同,但方法五花八门,而且调用api方法我至今没完全搞懂,只好摸索着用现在这个办法,记录一下。
思路:
1、树莓派利用api获取自己的公网ip
2、调用阿里云api将我的域名解析到当前树莓派的公网ip上,并且避免解析的地址相同(api会报错)
一、准备
1、树莓派 、阿里云的域名(便宜的几块钱一年)、有公网ip且可以设置端口映射的路由
2、安装阿里云的python版本的sdk,我这个只用了核心库,里面有api的泛用型调用命令。
https://developer.aliyun.com/tools/sdk?spm=5176.11122631.962077.5.d8f63801lb9te1#/python
我是直接用下面这个pip命令安装的,因为别的方法我不会,官方提供了一个httpdns的sdk。我估摸着应该是把方法都封装了更简便的样子。
3、得到你自己的AccessKey
在网页端阿里云控制台点击你的头像就能看到了,会生成一个AccessKey ID和Access Key Secret。这两个东西是过会调用api时验证你身份用的。
二、实施
1、获取树莓派当前的公网IP
调用网上找的获取IP地址的API,返回的就是自己访问公网的IP。我用的是这个: https://www.xxorg.com/tools/getip/
def getip():
res=request.urlopen('https://www.xxorg.com/tools/getip/')
return str(res.read(),'utf-8')
这个返回的就是自己公网的IP字符串。
2、构建客户端对象
构建一个包含你的AccessKey ID和Access Key Secret的客户段对象,后面会加到请求中
导入
from aliyunsdkcore.client import AcsClient
创建
client = AcsClient('你的AccessKey ID', '你的Access Key Secret', 'cn-hangzhou')
3、定义查询方法
导入
from aliyunsdkcore.request import CommonRequest
CommonRequest使用的介绍:
https://help.aliyun.com/document_detail/61476.html?spm=5176.10695662.1996646101.searchclickresult.61f2243bEt8PWL
def queryrecordid():
request = CommonRequest()
request.set_accept_format('json') #设置接收格式,有json和xml两种
request.set_domain('alidns.aliyuncs.com') #请求地址
request.set_method('POST') #请求方式,GET和POST两种
request.set_version('2015-01-09') #版本信息
request.set_action_name('DescribeDomainRecordInfo') #set_action_name这个是设置调用的方法
request.add_query_param('RecordId', '解析记录的ID') #request.add_query_param添加参数
response = client.do_action_with_exception(request)
return json.loads(str(response,'utf-8'))['Value'] #只读取返回数据中的value也就是IP
图中调用的时候应该有异常处理,但我对python还不熟悉,所以当时没敢搞,回头再来解决。
基本调用api就是更改一下action参数和参数的变化,具体的参数信息也都能从api文档里找到
解析记录的id需要调用DescribeDomainRecords获取解析记录的方法,可以调用之后记下来,后面只需要对这条记录进行更改和查询就行了。
def querylist():
request=CommonRequest()
request.set_accept_format('json')
request.set_domain('alidns.aliyuncs.com')
request.set_method('POST')
request.set_version('2015-01-09')
request.set_action_name('DescribeDomainRecords')
request.add_query_param('DomainName','你的域名')
response=client.do_action_with_exception(request)
print(str(response,'utf-8'))
4、定义更新方法
def updaterecordid(value):
request = CommonRequest()
request.set_accept_format('json')
request.set_domain('alidns.aliyuncs.com')
request.set_method('POST')
request.set_version('2015-01-09')
request.set_action_name('UpdateDomainRecord')
request.add_query_param('RecordId', '解析记录ID')
request.add_query_param('RR', '*')
request.add_query_param('Type', 'A')
request.add_query_param('Value', '解析到的IP地址') #上面三个值的解释都在api文档
response = client.do_action_with_exception(request)
api地址:https://help.aliyun.com/document_detail/29774.html?spm=a2c4g.11186623.6.641.7b435eb4WHrsn4
5、防止解析到同一个地址
ip=getip()
oldip=queryrecordid()
if oldip!=ip:
updaterecordid(ip)
print('The new IP is',ip)
else:
print("IP address not updated")
网上有的方法是直接将上次解析的地址写入本地,这样就可以减少api的调用次数,不过我水平有限也不太喜欢在本地再生成一个文件,于是就直接用当前地址和解析记录中的地址对比了。
6、部署
因为我家的路由和派是在同一个插排上的,所以每次开启路由器时树莓派也一块启动,这样就可以把这个代码放到树莓派的开机执行里运行,不过路由器开机时间长,所以我设置树莓派开机3分钟后自动执行。
执行命令
vi /etc/rc.local
加一段代码到exit 0之前
sleep 3m && python3 ddns.py &
休眠三分钟之后执行这个python程序,不过好像在rc.local中会阻塞开机,所以最后加一个&放到新的线程中运行
三、其他
在手机或者pc访问的时候会优先使用本机储存的dns缓存,所以更新的ip同步不过来,需要刷新dns缓存。win是在cmd中执行ipconfig /flushdns,手机直接飞行模式貌似就可以。