概述
家裡閒置著一臺老款的Mac mini Server,跑OS X越來越慢,索性裝上了Cent OS 7,變成了一臺家庭服務器,裝上了Plex媒體服務器和Transmission下載服務,同時,也裝上了Nginx、Mysql、MongoDB、Redis等,可以調試代碼,甚至擔當一些小型項目的服務器。
不過,只在家庭內網使用,功能太有限,於是接下來面臨的一個問題就是內網穿透。使用過花生殼和花生棒,服務相當不穩定,而且種種受限,每要多加一個端口就要多花錢,安全性也有問題。
其實想想,內網穿透的最大難題無非就是家裡是動態公網IP,每變換一次公網IP,需要重新解析一次域名。而阿里雲等大型的雲服務商,目前都已經實現了域名解析管理的API接口,而且基本都是立即就可生效 。
所以我的思路就是,系統運行一個定期執行的程序,每隔一段時間掃描一下最新的公網IP,如果發現最新的公網IP與域名解析到的IP地址不一致,就通過阿里雲API自動更新解析設置即可。這樣的花費不過每年一個域名的費用,最貴也就幾十塊錢。
具體實現步驟
- 阿里雲設置
首先,要確定一個準備用於外網訪問的域名,並將此域名轉入到阿里雲的雲解析服務來解析。如圖所示,添加需要管理的域名。
轉入後,在解析設置中,設置一下A記錄解析,解析的IP地址可以填當前的公網IP。如果不知道自己的公網IP,在CentOS系統下,可以輸入使用以下命令獲取當前的公網IP。
> curl ifconfig.me
獲取公網IP後,在阿里云云解析中設置完A記錄解析。
在阿里雲賬戶管理後臺,點擊右上角的賬戶頭像,然後點擊accesskeys,或者直接登陸 https://ak-console.aliyun.com,獲取阿里雲的AccessKeyID和AccessKeySecret。
- 路由器設置
阿里雲的設置完成後,需要對路由器設置端口映射,使外網對公網IP的端口訪問能轉發到內網服務器的相應端口。絕大部分的路由器都支持端口映射。
常見的服務端口包括,用於WEB訪問的80端口、SSH遠程管理的22端口、Mysql數據庫的3306端口、Transmission下載服務管理的9091端口和Plex媒體服務的32400端口等等。不用花生殼的好處就是沒有端口數量限制,想設置多少就可以設置多少。
當然,在設置端口映射之前,應確保服務器的內網IP已經設置為靜態IP,而不是DHCP動態獲取。
- 服務器設置
服務器端安裝好想要使用的各種服務後,別忘了在防火牆中開啟相應的端口,在CentOS 7中,防火牆永久開啟端口的命令是:
> firewall-cmd --add-port=80/tcp --permanent
開啟之後別忘了重新載入防火牆的設置以使其生效,命令如下:
> firewall-cmd --reload
- 自動更新域名解析程序
準備工作都做好了,接下來就是通過程序檢測公網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
- 設置定時運行
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
掃碼關注我,在線與我溝通、諮詢
轉載請保留原文鏈接以及版權信息