Loading... # 记录一次家庭内网使用DDNS让外网访问, 同时动态更新域名 相信很多同学在自己家里学习啥的搞些小网站小程序, 比如部署一些 `个人多媒体`、 `个人网盘`、 `个人博客`等的网站, 但是在公司时想访问记录或查询一些资料, 但是又因为访问不了家庭网络而烦躁... 在此分享能使用任意外网**访问家庭内网**, 同时**动态更新域名**的方法. ***当然在此之前我使用过花生壳、公云等一些软件, 他也可以让你从外网访问家庭内网, 但是别的不说, 他限速而且收费呀... 自己搭建可以全速使用家里的带宽*** 步骤如下: ## 一. 外网访问 <!-- more --> ### 1. 申请公网IP > 想访问家庭网络必定需要找家里开网络的运营商, 让他们给`开公网IP`, 我家里使用的是电信宽带, `电话直接打 10000 号人工服务让他们帮忙开通`, 理由嘛很简单( 找个借口说家里安装监控就给你开了 ) , 电信现在默认都是给的私网IP. ### 2. 光猫改为桥接模式 > 申请完公网IP先别急着挂, 还需要让他们把`宽带网络改成桥接模式`, 后面我们`路由器使用拨号上网` ### 3. 查询宽带账号和密码 > 由于路由器现在是使用拨号上网, 所以还需要找他运营商`拿到宽带的账户和密码`, 这些都是`必要条件` ### 4. 设备网线连接 > 我们使用网线连接 **光猫的网口** 和 **路由器WAN口**, 电脑主机的网线则联通路由器的LAN口, ( WAN口是连接外部网络, LAN口是连接内部网络, 家里的电脑网线都可以用LAN接口连接, 并且**此时我们电脑是没有网络的** ) > `光猫网口 --> 路由器WAN口` > `路由器LAN口 --> 电脑网口` ### 5. 设置路由器 > 此时已经具备的条件: > **`公网ip, 宽带改为桥接模式, 宽带账号和密码, 设备网线正确连接`** > - 开始设置路由器: > **`我的路由器设备使用的小米路由器, 暂以小米路由器为例`**, 路由器网关是 192.168.31.1 , 自己的路由器网关自己搜一下, 然后输入路由器用户名密码 > - 上网设置 > ![上网设置PPPoE拨号](/images/img-1.png) > 如图, 上网方式选择**`PPPOE手动拨号`**, 然后输入宽带的账号和密码即可 > 拨号成功应该就可以上网了~~~ ### 6. 检查IP地址 > 百度查询自己本机的IP是否与路由器拨号成功获得的IP地址相同. > **`如果不同, 那一般都是私网ip 没有申请公网ip的.`** > ![检查ip是否一致](/images/img-2.png) ### 7. 路由转发 > 一般路由器都拥有路由转发功能, 可以自己配置转发规则. > ![配置路由转发规则](/images/img-3.png) > - 端口转发: 映射端口, 访问外网 ip:端口, 会直接映射到内网的ip:端口 > 如: **访问外网地址 22.135.173.55:8848, 会被转发到内网 192.168.31.26:8000 ** > ![端口映射规则](/images/img-4.png) ### 8. 测试 > - 我本地电脑随便开启一个服务 > ![](/images/img-5.png) > 部署成功, 内网ip:port **192.168.31.26:8401** > ![启动成功啦, 内网IP访问](/images/img-6.png) > - 接着使用外网ip访问, **注意自己映射的端口哦** > ![外网IP访问](/images/img-7.png) > 访问成功~~ ## 二. 设置动态更新域名 由于电信给的公网IP是动态IP, 每次关闭重启光猫都会更换公网IP地址, 所以这也是个很头疼的事情... 小编提供个人解决方案: ### 1. 准备域名 ( 本方案只支持腾讯云域名, 对接腾讯云API ) > 我使用的方法, 使用Python写了一个脚本, 动态去更新域名, 需要准备一个腾讯云的域名。 > 提供购买链接 `https://buy.cloud.tencent.com/domain?from=console` ### 2. 开通腾讯云 API 密钥 > API 密钥代表你的账号身份和所拥有的权限,使用腾讯云 API 可以操作您名下的所有腾讯云资源。给上链接 https://console.cloud.tencent.com/cam/capi > > - 开通完后新建密钥( 单机即可, 自动创建 ): > ![新建腾讯云 API 密钥](/images/img-8.png) ### 3. 安装Python3 > 由于使用的 Python 写的脚本, 需要环境拥有Python, 版本 3 及以上. > 安装方法参考 https://www.cnblogs.com/weven/p/7252917.html > 安装完成后查看Python版本: > ![查看Python版本](/images/img-9.png) ### 4. 献上脚本 > ![upload successful](/images/img-10.png) > > - 复制以下代码 保存为 **xxx.py** 格式就行 ```python VERSION = 1 from hashlib import sha1 import json import time import base64 import hmac class DDnsHelper(): def __init__(self, mid=0, params={}): pass def excute(self): import requests SecretId = '*需要填写*' SecretKey = '*需要填写*' runningPause = 20 domainName = 'xxxx.com' # *需要填写你自己的域名* ddnsDomains = [ { # *需要填写你自己的域名* 'name': '@.xxxx.com', 'value': '', # 'always': False, # DNS生存时间 'ttl': 600, # 主机记录, 即域名前缀 'subDomain': '@', 'recordId': '', # 记录类型 'recordType': 'A', # 线路类型, 指定细分解析线路 'recordLine': '默认', 'description': '本地提供api服务的地址', # 查看本地域名的接口, 这是自己写的接口, 仅仅返回一个纯粹的本地外网IP地址 'localDomain': 'https://www.hosix.cn/ip', 'localValue': '' } ] class tenXunDDNS_Helper(): def __init__(self): self.running = True self.action = "" self.secretId = SecretId self.nonce = 38651 self.region = 'ap-guangzhou' self.secretKey = SecretKey self.version = '2017-03-12' self.domain = domainName self.url = 'cns.api.qcloud.com/v2/index.php' self.httpType = 'https://' self.endpoint = self.httpType + self.url self.ddnsDomain = ddnsDomains self.runningPause = runningPause self.remoteRecords = [] def getServerIp(self): timeStamp = int(time.time()) params = {} params['Action'] = 'RecordList' params['domain'] = self.domain params['Nonce'] = self.nonce params['SecretId'] = self.secretId params['Timestamp'] = timeStamp s = self.get_string_to_sign("GET", self.url, params) Signature = self.sign_str(self.secretKey, s, sha1) params['Signature'] = Signature response = requests.get(self.endpoint, params=params) result = json.loads(response.text) if int(result['code']) != 0: raise Exception('获取域名失败' + ':' + str(result['code']) + ':' + result['message']) data = result['data'] self.remoteRecords = data['records'] # print(self.remoteRecords) def postServerIp(self, domain): timeStamp = int(time.time()) params = {} params['Action'] = 'RecordCreate' params['domain'] = self.domain params['Nonce'] = self.nonce params['SecretId'] = self.secretId params['Timestamp'] = timeStamp params['subDomain'] = domain['subDomain'] params['recordType'] = domain['recordType'] params['recordLine'] = domain['recordLine'] params['value'] = domain['value'] params['ttl'] = domain['ttl'] s = self.get_string_to_sign("GET", self.url, params) Signature = self.sign_str(self.secretKey, s, sha1) params['Signature'] = Signature response = requests.get(self.endpoint, params=params) result = json.loads(response.text) if int(result['code']) != 0: raise Exception('添加域名失败' + ':' + str(result['code']) + ':' + result['message']) data = result['data'] print('添加域名成功ip:%s,本地ip:%s,域名:%s' % (domain['value'], domain['localValue'], domain['name'])) def updateServerIp(self, domain): timeStamp = int(time.time()) params = {} params['Action'] = 'RecordModify' params['domain'] = self.domain params['Nonce'] = self.nonce params['SecretId'] = self.secretId params['Timestamp'] = timeStamp params['subDomain'] = domain['subDomain'] params['recordId'] = domain['recordId'] params['recordType'] = domain['recordType'] params['recordLine'] = domain['recordLine'] params['value'] = domain['localValue'] params['ttl'] = domain['ttl'] s = self.get_string_to_sign("GET", self.url, params) Signature = self.sign_str(self.secretKey, s, sha1) params['Signature'] = Signature response = requests.get(self.endpoint, params=params) result = json.loads(response.text) if int(result['code']) != 0: raise Exception('更新域名失败' + ':' + str(result['code']) + ':' + result['message']) data = result['data'] print('更新域名成功源ip:%s,本地ip:%s,域名:%s' % (domain['value'], domain['localValue'], domain['name'])) def deleteServerIp(self): pass def getLocalDomain(self, domain): res = requests.get(domain['localDomain']) ip = res.content.decode("utf-8").strip() return ip def clearDnsRecord(self): for domain in self.ddnsDomain: if not domain['always']: domain['value'] = '' domain['localValue'] = '' def run(self): self.getServerIp() for domain in self.ddnsDomain: if (not domain['always']): # 获取本地ip try: domain['localValue'] = self.getLocalDomain(domain) except Exception as e: print("获取本地ip失败 不更新:%s,本地ip:%s,域名:%s" % ( domain['value'], domain['localValue'], domain['name'])) else: continue flag = False for remoteDomain in self.remoteRecords: if (domain['subDomain'] == remoteDomain['name']): domain['recordId'] = remoteDomain['id'] domain['value'] = remoteDomain['value'] flag = True break if flag: if (domain['value'] == domain['localValue']): pass # print("无需更新ip:%s,本地ip:%s,域名:%s" % (domain['value'],domain['localValue'],domain['name'])) else: self.updateServerIp(domain) continue else: domain['value'] = domain['localValue'] self.postServerIp(domain) self.clearDnsRecord() def start(self): start_time = int(time.time()) while self.running: next_time = int(time.time()) + self.runningPause if (next_time - start_time) > self.runningPause: try: self.run() except Exception as e: print(e.__str__()) start_time = start_time + self.runningPause else: time.sleep(self.runningPause / 10) def get_string_to_sign(self, method, endpoint, params): s = method + endpoint + "?" query_str = "&".join("%s=%s" % (k, params[k]) for k in sorted(params)) # print(s + query_str) return s + query_str def sign_str(self, key, s, method): hmac_str = hmac.new(key.encode("utf8"), s.encode("utf8"), method).digest() return base64.b64encode(hmac_str) t1 = tenXunDDNS_Helper() t1.start() d = DDnsHelper() d.excute() ``` > - 最后双击运行~ OK ### 5. 运行原理和注意事项 > - -**原理:** `该脚本是通过定时查询公网IP接口: https://www.hosix.cn/ip , 然后调用腾讯云API去动态更新域名. 非常简单.....` > - **注意事项:** > 1.`该脚本需要持续运行`, 如果是Linux系统, 直接挂后台运行即可, 该脚本资源消耗不高 > 2.如果提示没安装 `requests` 模块, 打开cmd窗口 > 输入: **`pip install requests`** > ![pip install requests](/images/img-12.png) > 3.如运行闪退, 请检查域名等是否正确填写 如有问题请评论或留言: 544010165@qq.com 最后修改:2022 年 07 月 01 日 © 允许规范转载 赞 32 如果觉得我的文章对你有用,请点个赞吧~
3 条评论
有用, 家里千兆网快的飞起, 赞一个 ::tieba:Y.tb10::
优秀
66666