引
一直想利用樹莓派親手搭建幾種伺服器來加深了解,奈何電信光貓每次重新開機後都會重新配置設定公網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,手機直接飛行模式貌似就可以。