如果将PC电脑变成web服务器:使用python3监测公网IP实现DDNS
上一篇文章中,我们使用Nignx的反向代理和端口转发实现域名访问家里主机上的web了。
由于家庭宽带基本都是动态IP,每当你重启一次光猫,IP地址就会变化一次。当光猫因为停电、故障、维护等原因重启过后,网站就无法访问了。网上基本的解决方法是使用花生壳做DDNS(动态域名解析),但那个需要绑定自己的域名要付费不说,且linux无法使用,本文通过python和socket实现DDNS。
(因平台原因本文中www即为xxx ,com即为zzz,http/ccccc即为cccc/ccccc)
这个程序是一个典型的C/S程序,有客户端和服务端。画张草图来解释下这个python程序的运行原理:
说明:这个程序分为客户端和服务端。客户端运行在内网主机上,服务端运行在服务器上。客户端会每隔30秒主动检测一次自己的公网IP是否变化,如果地址改变,则会通过socket连接服务端程序,把改变后的地址发送给服务端。服务端接收到地址后,先校验一遍地址是否合fa,如果地址OK,那么将地址写入Nginx的反代理配置文件,反代理生效并指向新的内网主机公网地址,从而实现DDNS。
一、程序的使用环境
服务器系统需是centos7,内网主机可以是windows或者centos7。
注意:程序是使用python3开发的,不兼容python2。因此如果使用centos7默认自带的python2运行会报错。
1. 服务端环境:python3、retry模块。
python3环境搭建请看主页
搭建完成后,使用pip安装retry模块:
pip install retry
2. 客户端环境:python3、beautifulsoup4模块、retry模块
这里演示一下windows怎么安装python3和模块。
windows版python3地址:ccccc://xxx.python.org/ftp/python/3.6.5/python-3.6.5-amd64.exe
直接打开安装,记得把下图箭头的地方勾上:
装完了win+R运行cmd,打开命令提示符窗口,输入python -V。有如下回显表示成功:
然后我们更新一下pip版本到10.0.1,默认的是9.0.3:
python -m pip install --upgrade pip
安装retry和beautifulsoup4模块
pip install retry
pip install beautifulsoup4
二、程序运行
1.服务端
服务端运行在服务器地址上,使用以下命令即可下载运行。
wget ccccc://xxx.27server.zzz/shell/ddns_server.py ;
python3 ddns_server.py
如图,程序运行后输入上一篇文章你绑定的域名和反代理的端口号,程序会实时监听。
2. 客户端
客户端以windows为例:
程序地址:ccccc://xxx.27server.zzz/shell/ddns_client.py
将下载好的程序放到D盘根目录,然后打开cmd执行以下命令:
d:
python ddns_client.py
如图,程序运行后输入服务端的地址,即可开始工作:
这样我们就实现了ddns了。当运行在内网主机上的客户端检测到自己的公网IP变更,则会主动把变更后的IP发送给云服务器上的服务端,服务端检测无误后,将地址写入nginx的配置文件。无论家庭的公网IP怎么变化,都可以正确指向。
运行截图(中间重启了光猫):
我们通过socket随便发个不是IP地址的文本给服务端:
服务端只会接受正确的IP地址格式,并写入配置文件,防止出错。
三、源码
#coding=utf-8
import timeimport socketfrom retry import retryimport os
os.system('clear')
server_name=str(input('输入你的网址:'))
port=int(input('输入反代理端口号(1-65535):'))if port > 65535:
print('端口不合fa!')
exit()elif port <1:
print('端口不合fa!')
exit()
@retry()def recv_ip():
sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_TCP)
addr=('0.0.0.0',8888)
sk.bind(addr)
sk.listen(1)
conn,addr=sk.accept()
global new_ip
new_ip=conn.recv(30).decode()
#sk.sendto(send_data,addr)
sk.close()
conn.close()
if len(new_ip)>15:
print('地址不合fa!')
elif len(new_ip)<8;
print('xxx')
else:
print("客户机公网地址变更:",new_ip)
def write_to():
proxy='server{\nlisten 80;\nserver_name xxx.27server.com;\nlocation / {\n proxy_pass cccc://'+new_ip+':'+str(port)+';\n} \n access_log off;\n }';
os.remove('/usr/local/nginx/conf/vhost/'+server_name+'.conf')
f=open('/usr/local/nginx/conf/vhost/'+server_name+'.conf','w',encoding='utf-8')
f.write(proxy)
f.close()
print("----写入配置文件成功----")
os.system('service nginx restart')
print("已生效,当前反代理规则为:"+new_ip+':'+str(port))
print('\n------继续监听ing..------')
print("开始监听客户机")
recv_ip()
write_to()
i=0while i==0:
time.sleep(5)
recv_ip()
if new_ip == None:
print('地址不能为空!')
continue
elif new_ip==[]:
print('禁止元素!')
continue
elif len(new_ip) >15:
print('地址过长!')
continue
elif len(new_ip)<8:
print('非fa地址!')
continue
else:
write_to()
2. client端
#coding=utf-8#author:aixi#blog:ccccc://xxx.27server.zzz/
import urllib.requestfrom bs4 import BeautifulSoupimport socketimport timefrom urllib.error import URLErrorfrom retry import retry
ip_addr=str(input('输入服务端IP:'))
ip_port=8888#ip_port=int(input('输入服务端端口(1-65535):'))#if ip_port > 65535:# print('端口不合fa!')# exit()#elif ip_port <1:# print('端口不合法!')# exit()
@retry()def get_ip():
url = 'cccc://xxx.net.cn/static/customercare/yourip.asp'
req = urllib.request.Request(url)
rsp=urllib.request.urlopen(req)
html=rsp.read().decode('utf-8',"ignore")
html=BeautifulSoup(html,'html.parser')
iph2=html.h2
global ip
ip=iph2.get_text()
#print("你的公网IP是:",ip)
@retry()def send_ip():# ip_addr='alish02.ssrcn.me'
addr=(ip_addr,ip_port)
sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_TCP)
sk.connect(addr)
sk.send(ip.encode())
sk.close()
print("\n----开始侦测本机公网IP地址----")
get_ip()
send_ip()
i=0while i == 0:
get_ip()
print ("当前公网IP:",ip)
tmp1_ip=ip# print("tmp1_ip:",tmp1_ip)
print("------休息30秒------")
time.sleep(30)
get_ip()
tmp2_ip=ip# print("tmp2_ip:",tmp2_ip)
if tmp1_ip == tmp2_ip:
print("########OJBK,地址没变!########")
else:
ip=tmp2_ip
print("公网地址改变:",ip)
send_ip()
print("同步到远程服务器成功!")
print("\n########继续检查########")
我是艾西,今天的分享就到这里啦希望对有需要的小伙伴有帮助我们下期见
拥有一台服务器可以做很多有趣的事情!