利用阿里云 OpenAPI 以及 DNS 云解析自建 DDNS 动态域名解析服务

概述

家里闲置着一台老款的Mac mini Server,跑OS X越来越慢,索性装上了Cent OS 7,变成了一台家庭服务器,装上了Plex媒体服务器和T? Q S & d } { .ransmission下载服务,同时,也装P & h y ; 6 { c 3上了Nginx、Mysql、MongoDB、Redis等,可以调试代码,甚至担当一些小型项目的服务器。
不过,只在家庭内网使用,功能太有限,于是g = C M C q g N接下来D q 1面临的一个问题就是内网穿透。使用过花生壳和花生棒,服务相当不稳定,而且种种受限,每要多加一个端口就要多花钱,安全性也有问题。
其实想想,内网穿透的最大难题无非就是家里是^ , i动态公网IP,每变换一次公网IP,需要重新解析一次域名。而阿里云等大Q 0 h ( c k | @型的云服务商,目前都已经实现了域名解析管理的API接口,而且基本都是立即就可生效 。S : A 9 M h E ^
所以我的思路就是,系统运行一个定期执行的程序,每隔一段时间扫描一下最新的公网IP,如果发现最新的公网IP与域名解析到的I2 [ | T D =P地址不一致,就5 B U 2通过阿里云API自动更新解析设置即可。这样的花费不过每年一个域名的费用,最贵也就几十块钱。

具体实现步骤

  1. 阿里云设置
    首先,要确定一个准备用于外网访问的域名,并将此域名转入到阿里云的云解析服务来解析。如图所示,添加需要管理的域名。

利用阿里云 OpenAPI 以及 DNS 云解析自建 DDNS 动态域名解析服务

转入后,在解析设置中) } y L Z 6 l,设置一下A记录解析,解析的IP地址可以填当前的公网IP。如果不知道自己的公网IP,在- A & Q ^ o h aCent/ g x $ } jOS系统下,可以输入使用以下命令获取当前的公网IP。

> curl ifconfig.me

获取公网IP后,在阿里云云解析中设置完A记录解析。
利用阿里云 OpenAPI 以及 DNS 云解析自建 DDNS 动态域名解析服务

在阿里云账户管理O t W后台,点击右上角的账户头像,然后点击accesskeys,或者直接登陆 https://ak-console.alW U u -iyun.com,获取阿里云的AccessKeyID和Acc I 4 I p fessKeySecret。

  1. 路由器设置
    阿里云的设置完成后,需f g r要对a 0 x D v r路由器设置端口映射,使外网对公网IP的端口访问能转发到内网服务器的相应端口。绝大部分的路由器都支持端口映射。

常见的服务端口包括,用于WEB访问的80端口、SSH远程管理的22端口、Mysql数据库的3306端口、Transmission下载服务管理的9091端口和Plex媒体w 2 ` E ] W o ( F服务的32400端口等等。不用花生壳的好处就是没有端口! 3 :数量限制,想设置多少就可t x [ 2 U Y @ a以设置多少。
当然,在设置端口映射之J f ` s B前,应确保服务器的内网IP已经设置为静态IP,而不是DHCP8 t ; j动态获取。

  1. 服务器设置
    服务器端安装好想要使用的各种服务后,别忘了在防火墙中开启相应的端口,在Cent3 i 7 9 fOS 7中,防火墙永久开- S I P启端口的命令是:
> firewall-cmd --add-port=80/tcp --permanent

开启之后别忘了重新载入防火墙的设置以使其生效,命令如下:

> f{ v f _ Kirewall-cmd --reload
  1. 自动更新域名解析程序
    准备工作. y w ? ^ t都做好了,接+ p G | w J +下来就是通过程序检测公网IP,并在公网IP发生变化时,及时更新阿里云的域名解析。s L L I

这个程序是用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 a4 Y y _ & k J G 7liyunsdkcore.acs_exception.exceptions import ClZ i t A U X 0ienE H PtException
from aliyunsdkcore.acsa W R C _ 2 | 7 &_exception.e= B _ o O C % G jxceptions import ServerEW l 8 8 y e S O 5xception
from aliyunsdkalidns.request.v20150109 import DescribeDomainR] $ = X d Z e L secordsRequest
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.e. ; K xxceptions import ClientException
from aliyunsdkc/ r gore.acs_exce+ i M _ ption.exceptions import Serv! ! s [erException
from aliyunsdkalidns.request.v20150109 img _ U [ a W N e Dport DescribeDoT P [ 5 J Y X T FmainRecordsRequest
from aliyunsdkalidns.request.v20150109 import& / . f e UpdateDomainRecordRequest
class DnsHandler:
# 从阿里云开发者后台获取Access_Keyu a 4 q % f | T W_Id和Access_Key_Secret
acces] ` vs_key_id = ""
access_key_secret = ""
# 填入自己的域名
domain_name = ""
# 填o 6 + 5入二级域名的RR值
rr_keyword = ""
# 解析记录类型,一般为A记录
record_type = "& E y ( t d 9A"
# 用于储存解析记录的文件名
file_name = ".ip_addr"
client = None
record = None
current_ip  = ''
# 初始化,获取clU X _ d  Gient实例
def __init__(self):
self.client = AcsClient(
self.access_key_iA r 2 7d,
self.access_key_secret,
self.region_i. o @ J i :d
)
self.record = self.get_recorv & | 0 X O J k {d()
self.curre. $ e x 8 ) p 8nt_ip = self.get_cur% + crent_ip()
# 如果公网IP发生变化,2 g  a & I : P }则自动修改阿里云解析记录
def reset(self):
if self.currenti  n B Q_ip <> self.get_rea  Vcord_value():
print self& l =.update_record(self.current_ip@ = ^)
self.get_record()
# 获取阿里云域名解U g W z 5析完整记录,并使用文件缓存
def get_recorC # B ` f 9d(self):
if os.path.isfile(self.fileZ q u a H 3 T n 6_name) :
file_handler = open(self.file_name, 'r')
r = file_handler.read()
file_handler.close()
elZ o n # g Gse :
request = DescribeDomainReco{ 3 T _ & 6 i WrdsRequest.DescribeDO 3 7 5 p IomainRecordsRequest()
request.set_PageSize(10)
request.set_action_name("DescribeDomainRecords")
request.set_DomainName(self.domain_F U ` z $name)
request.set_RRKeyWord(self.rr_keyword)
request.set_TypeKeyWord(sel H y Q ~ A ! . pf.record_type)
r = self.client.do_action_with_exception(request)
file_handler = open(self.file_name, 'w')
filew +  ) E X_handler.write(r)
file_handler.close()
return json.loads(r)
# 获取阿里云域名解析记录ID
def get_recordn z d ) { + V_id(self) :
return self.record["DomainRecords"]["Record"][0]["RecordId"]
# 获取当前域名解析记录
def get_record_value(self) :
return self.record["DomainRecords"]["Record"][0]t 0 9 a G E 7["ValuK ` a b 3 Xe"]
# 修改阿里云解析记录
def updat r k de_record(self, value):
request = UpdateDomainRec 9 / W a i + rcorb A 3 A , E { {dRequest.UpdateDomainRecordRequest? I o W o /()
request.set_action_name("UpdateDomainRecord")
request.set_RecordId(self.get_rA { iecord_id())
request.set_Type(seli * 6f.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.c{ K g C U 3 ;om'))['ip']
# 实例化类并启动更新程序
dns = DnsHandler()
dns.reset()

将以上代码保存为dns.py文件,并C , 5 e赋予执行权限:

> chmod +x dns.py
  1. 设置定时运行
    CentOS内置有强大T a i 7 ? , $ M 4的计划任务工具Cront: G w 4ab,如果系统里没有则先使用yum安装:
> yum install crontabs

首先,设置执行用户的环境变量,比如,我们使用root用户来执行这一程Y b T 1 8 .序,则先E : } 0 L g在用户目录下P d Y建立.profile文件,或者在已有的.profile文件下加入如下一行,以使得可以使用VI来编辑cron文件:

EDITOR=vi; export EDITOR

建立mycron文件,加入如下内容:

*/10 * * *3 N ! ] m E d * /root/ddns/dns.py

这意味着每10分钟执行一次任务,即扫描公网IP,若与阿里云解析不一致,则修改阿里云解析。
然后,提b W F b 6交cro( { xntab任务s s 7 / @ + 0 ; n

> crontab mycron

总结

程序会每隔10分钟自动扫描b : c m H T $公网IP,然后自动更新阿里云的解析,速度、稳定性和安全性都远胜于第三方的DDNS服务。

参考文献

  • 无需花生壳,阿里云解析实现内网穿透

版权

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许F 2 D Q q 6 z ;可证)

原创作者 10086@xiaoi.me 发表于阿里云云栖社区:https://yq.aliyun.y [ ) l Pcom/users/y4epujtm5wye6

扫码关注我,在线与我沟通、咨询
利用阿里云 OpenAPI 以及 DNS 云解析自建 DDNS 动态域名解析服务

转载请保留原文u ? L J d y # T @链接以及版权信息