家里的宽带是电信的。电信的宽带比联通或是移动的是贵一些,但有一个优点是可以比较简单的申请到公网ip。有了公网ip之后,我们就可以用来做一些有趣的事情,比如远程登录到家里的台式机,访问家里的黑群晖。

但需要注意的是,这个ip是不固定的,即重新拨号之后,地址将会变掉。虽然略有不方便的地方,但搭配上路由器的DDNS功能和端口转发功能,就可以使用域名来访问到这个地址下开通的服务。

最近一段时间,不知道什么原因,路由器的ddns注册功能总是异常,表现为域名注册失败。这下,在外面再也不能简单的连到家里的网络了。虽然可以通过公网ip来进行连接,但这建立在我记住了最新的ip而路由器没有重新拨号的前提下。

这几天,由于沉迷看芙莉莲,发生了几次兴冲冲想要打开emby server但却连不上的尴尬局面。也许是时候想办法解决这个问题了。首先我对ddns注册不上的问题毫无思路,我只能=退而求其次,从同步获取最新的公网ip地址方向来解决。

我的整体思路是,使用python脚本的方式来进行实现:

  1. 脚本持续运行。
  2. 每隔1个小时执行一次获取ip的操作。
  3. 和上次获取的ip进行比较,如ip不同,则将新的ip发送到指令的邮箱。
  4. 部署方案采用docker镜像的方式,部署在nas中。

首先是如何获取到公网ip。从路由器的管理台倒是能够直接查看到,但想要程序获取的话,就需要处理登录、session等等相关的问题,略显麻烦,放弃。

在google的帮助下,找到了一个可以展示ip的web页面:https://2024.ip138.com。查看了之后,确认可以正确的展示公网ip。就选择你了。

获取ip的问题解决了之后,剩下的工作就十分简单了。在chatgpt的帮助下,十分钟不到就完成了脚本的编写。其中,main 函数是脚本主题逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

import os
import smtplib
import time
from datetime import datetime

from email.mime.text import MIMEText
from email.header import Header

import requests
from bs4 import BeautifulSoup


def get_public_ip():
"""
获取公网ip地址
:return:
"""
headers = {
'User-Agent': 'PostmanRuntime/7.26.8',
'Accept': '*/*',
'Accept-Encoding': 'gzip,deflate,br',
'Connection': 'keep-alive'
}

get_ip_url = 'https://2024.ip138.com'
resp = requests.get(get_ip_url, headers=headers)
html=resp.text
bs = BeautifulSoup(html, 'html.parser')
title = bs.find_all('title')
if len(title) > 0:
text = title[0].text
return text.split(':')[-1]


def send_email(sender, password, receiver, content):
"""
使用sender向receiver发送邮件
:param sender: 发送方
:param password: 发送方token
:param receiver: 接收方
:param content: 内容
:return:
"""
if not content:
print('no content to send')
return
subject = f'Today\'s ip is {content}, and now is {str(datetime.now())}'
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = Header(sender, 'utf-8')
message['To'] = Header(receiver, 'utf-8')
message['Subject'] = Header(subject, 'utf-8')

try:
smtp_obj = smtplib.SMTP_SSL('smtp.163.com', 465)
smtp_obj.login(sender, password)
smtp_obj.sendmail(sender, receiver, message.as_string())
print('send successfully.')
except smtplib.SMTPException as e:
print(e)
finally:
smtp_obj.close()


def main():
previous_ip = ''
sender = os.getenv('sender')
password = os.getenv('password')
receiver = os.getenv('receiver')
if not sender or not password or not receiver:
print('no environment variables')
return -1
while True:
try:
ip = get_public_ip()
except Exception as e:
print(e)
else:
if previous_ip != ip:
previous_ip = ip
try:
send_email(sender, password, receiver, ip)
except Exception as e:
print(e)
else:
print('no difference since last fetched.')
print('now, sleep for 1 hours')
time.sleep(60 * 60)


if __name__ == '__main__':
main()

前面的环节一切顺利,到了制作docker镜像的时候遇到了点麻烦。我需要选择一个包含python执行环境的docker镜像,但pull镜像的时候才发现,包含python运行环境的基础镜像都有7、8百兆之大。为了我这么一个小小的需求,这未免有些太过于劳师动众了。后面,灵机一动,想到了将脚本打包的方式。通过使用pyinstaller对脚本进行了打包。

使用pyinstaller对脚本进行打包的方式是:

1
pyinstaller -F -p ".venv/Lib/site-packages" ../main.py

最终得到了一个80M作用的镜像。

1
2
3
4
5
6
7
FROM ubuntu:20.04
MAINTAINER maslke
ENV TZ=Asia/Shanghai
COPY spec/dist/main /root
WORKDIR /root
CMD ["./main"]

最后,在docker中创建容器的时候,设置好senderreceiverpassword环境变量,即可正常启动运行了。需要注意的是,发送邮箱需要开启smtp服务。

至此,问题完美解决。




👨‍💻本站使用 Stellar 主题创建

📃本"页面"访问 次 | 👀总访问 次 | 🥷总访客

⏱️本站已运行 小时