天天看點

利用阿裡雲 OpenAPI 以及 DNS 雲解析自建 DDNS 動态域名解析服務概述具體實作步驟總結參考文獻版權

概述

家裡閑置着一台老款的Mac mini Server,跑OS X越來越慢,索性裝上了Cent OS 7,變成了一台家庭伺服器,裝上了Plex媒體伺服器和Transmission下載下傳服務,同時,也裝上了Nginx、Mysql、MongoDB、Redis等,可以調試代碼,甚至擔當一些小型項目的伺服器。

不過,隻在家庭内網使用,功能太有限,于是接下來面臨的一個問題就是内網穿透。使用過花生殼和花生棒,服務相當不穩定,而且種種受限,每要多加一個端口就要多花錢,安全性也有問題。

其實想想,内網穿透的最大難題無非就是家裡是動态公網IP,每變換一次公網IP,需要重新解析一次域名。而阿裡雲等大型的雲服務商,目前都已經實作了域名解析管理的API接口,而且基本都是立即就可生效 。

是以我的思路就是,系統運作一個定期執行的程式,每隔一段時間掃描一下最新的公網IP,如果發現最新的公網IP與域名解析到的IP位址不一緻,就通過阿裡雲API自動更新解析設定即可。這樣的花費不過每年一個域名的費用,最貴也就幾十塊錢。

具體實作步驟

  1. 阿裡雲設定

    首先,要确定一個準備用于外網通路的域名,并将此域名轉入到阿裡雲的雲解析服務來解析。如圖所示,添加需要管理的域名。

利用阿裡雲 OpenAPI 以及 DNS 雲解析自建 DDNS 動态域名解析服務概述具體實作步驟總結參考文獻版權

轉入後,在解析設定中,設定一下A記錄解析,解析的IP位址可以填目前的公網IP。如果不知道自己的公網IP,在CentOS系統下,可以輸入使用以下指令擷取目前的公網IP。

> curl ifconfig.me           

擷取公網IP後,在阿裡雲雲解析中設定完A記錄解析。

利用阿裡雲 OpenAPI 以及 DNS 雲解析自建 DDNS 動态域名解析服務概述具體實作步驟總結參考文獻版權

在阿裡雲賬戶管理背景,點選右上角的賬戶頭像,然後點選accesskeys,或者直接登陸

https://ak-console.aliyun.com

,擷取阿裡雲的AccessKeyID和AccessKeySecret。

  1. 路由器設定

    阿裡雲的設定完成後,需要對路由器設定端口映射,使外網對公網IP的端口通路能轉發到内網伺服器的相應端口。絕大部分的路由器都支援端口映射。

常見的服務端口包括,用于WEB通路的80端口、SSH遠端管理的22端口、Mysql資料庫的3306端口、Transmission下載下傳服務管理的9091端口和Plex媒體服務的32400端口等等。不用花生殼的好處就是沒有端口數量限制,想設定多少就可以設定多少。

當然,在設定端口映射之前,應確定伺服器的内網IP已經設定為靜态IP,而不是DHCP動态擷取。

  1. 伺服器設定

    伺服器端安裝好想要使用的各種服務後,别忘了在防火牆中開啟相應的端口,在CentOS 7中,防火牆永久開啟端口的指令是:

> firewall-cmd --add-port=80/tcp --permanent           

開啟之後别忘了重新載入防火牆的設定以使其生效,指令如下:

> firewall-cmd --reload           
  1. 自動更新域名解析程式

    準備工作都做好了,接下來就是通過程式檢測公網IP,并在公網IP發生變化時,及時更新阿裡雲的域名解析。

這個程式是用Python寫的,先使用Python的包管理工具pip下載下傳安裝阿裡雲的Python SDK。如果沒有安裝pip,則先安裝pip:

> yum install pip           

安裝好pip後,安裝阿裡雲的Python核心SDK以及雲解析SDK:

> pip install aliyun-python-sdk-core
> pip install aliyun-python-sdk-alidns           

導入項目所需要的包,如果缺少則使用pip安裝:

import os
import json
from urllib2 import urlopen
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109 import UpdateDomainRecordRequest           

完整代碼如下:

#!/usr/bin/env python
# coding= utf-8

import os
import json
from urllib2 import urlopen
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkalidns.request.v20150109 import DescribeDomainRecordsRequest
from aliyunsdkalidns.request.v20150109 import UpdateDomainRecordRequest

class DnsHandler:
    # 從阿裡雲開發者背景擷取Access_Key_Id和Access_Key_Secret
    access_key_id = ""
    access_key_secret = ""

    # 填入自己的域名
    domain_name = ""
    # 填入二級域名的RR值
    rr_keyword = ""

    # 解析記錄類型,一般為A記錄
    record_type = "A"

    # 用于儲存解析記錄的檔案名
    file_name = ".ip_addr"

    client = None
    record = None
    current_ip  = ''

    # 初始化,擷取client執行個體
    def __init__(self):
        self.client = AcsClient(
            self.access_key_id,
            self.access_key_secret,
            self.region_id
        )
        self.record = self.get_record()
        self.current_ip = self.get_current_ip()

    # 如果公網IP發生變化,則自動修改阿裡雲解析記錄
    def reset(self):
        if self.current_ip <> self.get_record_value():
            print self.update_record(self.current_ip)
            self.get_record()

    # 擷取阿裡雲域名解析完整記錄,并使用檔案緩存
    def get_record(self):
        if os.path.isfile(self.file_name) :
            file_handler = open(self.file_name, 'r')
            r = file_handler.read()
            file_handler.close()
        else :
            request = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
            request.set_PageSize(10)
            request.set_action_name("DescribeDomainRecords")
            request.set_DomainName(self.domain_name)
            request.set_RRKeyWord(self.rr_keyword)
            request.set_TypeKeyWord(self.record_type)
            r = self.client.do_action_with_exception(request)
            file_handler = open(self.file_name, 'w')
            file_handler.write(r)
            file_handler.close()
        return json.loads(r)

    # 擷取阿裡雲域名解析記錄ID
    def get_record_id(self) :
        return self.record["DomainRecords"]["Record"][0]["RecordId"]

    # 擷取目前域名解析記錄
    def get_record_value(self) :
        return self.record["DomainRecords"]["Record"][0]["Value"]

    # 修改阿裡雲解析記錄
    def update_record(self, value):
        request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
        request.set_action_name("UpdateDomainRecord")
        request.set_RecordId(self.get_record_id())
        request.set_Type(self.record_type)
        request.set_RR(self.rr_keyword)
        request.set_Value(value)
        return self.client.do_action_with_exception(request)

    # 擷取目前公網IP
    def get_current_ip(self):
        return json.load(urlopen('http://jsonip.com'))['ip']

# 執行個體化類并啟動更新程式
dns = DnsHandler()
dns.reset()           

将以上代碼儲存為dns.py檔案,并賦予執行權限:

> chmod +x dns.py           
  1. 設定定時運作

    CentOS内置有強大的計劃任務工具Crontab,如果系統裡沒有則先使用yum安裝:

> yum install crontabs           

首先,設定執行使用者的環境變量,比如,我們使用root使用者來執行這一程式,則先在使用者目錄下建立.profile檔案,或者在已有的.profile檔案下加入如下一行,以使得可以使用VI來編輯cron檔案:

EDITOR=vi; export EDITOR           

建立mycron檔案,加入如下内容:

*/10 * * * * /root/ddns/dns.py           

這意味着每10分鐘執行一次任務,即掃描公網IP,若與阿裡雲解析不一緻,則修改阿裡雲解析。

然後,送出crontab任務:

> crontab mycron           

總結

程式會每隔10分鐘自動掃描公網IP,然後自動更新阿裡雲的解析,速度、穩定性和安全性都遠勝于第三方的DDNS服務。

參考文獻

版權

版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)

原創作者 [email protected] 發表于阿裡雲·雲栖社群:

https://yq.aliyun.com/users/y4epujtm5wye6

掃碼關注我,線上與我溝通、咨詢

利用阿裡雲 OpenAPI 以及 DNS 雲解析自建 DDNS 動态域名解析服務概述具體實作步驟總結參考文獻版權

轉載請保留原文連結以及版權資訊

繼續閱讀