利用DNSPodAPI实现服务器DDNS解析
DDNS是将用户的动态IP地址映射到一个固定的域名解析服务上,用户每次连接网络的时候客户端程序就会通过信息传递把该主机的动态IP地址传送给位于服务商主机上的服务器程序,服务器程序负责提供DNS服务并实现动态域名解析。
一句话:把动态变化的IP地址绑定到固定不变的域名上,以不变应万变。
博主找了很多DNSPOD的API脚本,一部分已经是几年前开发的了,运行起来会出现各种问题,后面找到一个完美版本,分享给大家。
从实际上来说,为什么我们会需要DDNS服务?
现阶段的HKT和Hinet的NAT机器非常流行,一部分商家已经为我们做好了DDNS服务,我们只需要使用官方提供的域名即可,但是一部分商家不提供DDNS,而是为我们提供一个动态IP,当IP出现问题后,商家更换IP也不会通知我们。需要去后台查看,所以解决这个问题,就需要我们自建DDNS。
DNSPodAPI安装:
#!/usr/bin/env python # -*- coding:utf-8 -*- import socket import requests import time import logging logging.basicConfig(level=logging.WARNING) logger = logging.getLogger(__name__) class DNSPod(object): """DNSPod ddns application.""" def __init__(self, params): """Initialize with params.""" self._params = params def run(self, params=None): if params is None: params = self._params public_ip = self.get_public_ip() # get record_id of sub_domain record_list = self.get_record_list(params) if record_list['code'] == '10': # create record for empty sub_domain record_id = self.create_record(params, public_ip) remote_ip = public_ip elif record_list['code'] == '1': # get record id record_id = record_list['record_id'] remote_ip = record_list['ip_value'] else: logger.error('!!!can not get record_id!!!') return -1 params['record_id'] = record_id current_ip = remote_ip while True: try: public_ip = self.get_public_ip() if current_ip != public_ip: logger.warning("update IP from %s to %s" % (current_ip, public_ip)) if self.ddns(params, public_ip): current_ip = public_ip else: logger.info("IP remains %s" % public_ip) except Exception as e: logger.error(e) pass time.sleep(300) def get_public_ip(self): """Get public ip via dnspod.""" sock = socket.create_connection(('ns1.dnspod.net', 6666), timeout=30) ip = sock.recv(16) sock.close() return ip.decode('utf-8') def get_record_list(self, params): """Get record list. https://www.dnspod.cn/docs/records.html#record-list :return: dict of code, record_id and IP value """ record_list_url = 'https://dnsapi.cn/Record.List' r = requests.post(record_list_url, data=params) code = r.json()['status']['code'] record_id = r.json()['records'][0]['id'] if code == '1' else "" ip_value = r.json()['records'][0]['value'] if code == '1' else "" return dict(code=code, record_id=record_id, ip_value=ip_value) def create_record(self, params, ip): """Create record if not created before. https://www.dnspod.cn/docs/records.html#record-create :return: record_id of new record """ params['value'] = ip record_create_url = 'https://dnsapi.cn/Record.Create' r = requests.post(record_create_url, data=params) logger.warning('create new record %s.%s with IP %s' % (params['sub_domain'], params['domain'], ip)) assert r.json()['status']['code'] == '1' record_id = r.json()['record']['id'] return record_id def ddns(self, params, ip): """Update ddns ip. https://www.dnspod.cn/docs/records.html#dns """ params['value'] = ip ddns_url = 'https://dnsapi.cn/Record.Ddns' r = requests.post(ddns_url, data=params) logger.info('status: %s, reason: %s' % (r.status_code, r.reason)) return r.json()['status']['code'] == '1' def main(): # initialize params # Use Token, check https://support.dnspod.cn/Kb/showarticle/tsid/227 ID = '请输入id' # replace with your ID Token = '请输入token' # replace with your Token params = dict( login_token=("%s,%s" % (ID, Token)), format='json', domain='请输入主域名', # replace with your domain sub_domain='需要解析的二级域名名字', # replace with your sub_domain record_type='A', record_line='默认' ) dnspod = DNSPod(params) dnspod.run() if __name__ == "__main__": main()
修改配置:
修改配置请替换文件中红色部分即可。举例子,我们有个域名叫 gov.cn,需要解析hinet.gov.cn到服务器中,所以后面这样填:
domain='gov.cn', # replace with your domain sub_domain='hinet', # replace with your sub_domain record_type='A', record_line='默认'
脚本在线下载:
wget https://cikeblog.com/e/ddns.py && chmod +x ddns.py
将文件存为ddns.py后,我们赋予执行权限:
chmod +x ddns.py
然后手动执行一次:
./ddns.py
测试无问题后,将其加入放入/home、目录下,并加入crontab定时任务,推荐为20分钟执行一次:
crontab -e */20 * * * * /home/ddns.py
请注意,请先为域名做一个A记录,填写内容为任意IP,脚本只能进行修改记录,无法为您创建一个子域名记录。
DNSPodAPI申请:
https://www.dnspod.cn/console/user/security
申请后,请记录下ID和token,此信息只会出现一次,然后进行文件替换即可。
注意,DNSPOD有个好处,我们手动修改域名信息的话,最低TTL为600,用脚本执行的话,TTL可以最低到10,这样解析会更快生效。
继续阅读