在有动态公网 IPV6 的情况下,使用 DDNS 和自定义端口对外提供 Web 服务并不难,但面临两个重要问题:
提供 Web 服务的方案有很多,比如使用端口映射方案。我曾使用过 fatedier/frp 这样的开源项目,但它需要另外维护一台 VPS,其带宽和成本都是问题。此外,端口映射的方案实际上也并不安全。
因此,我选择了另一种更加适合我目前场景的方案:
EdgeOne 的具体介绍可以查看腾讯云的产品介绍,这里不再赘述。可以简单将它看作一个更加安全的 CDN。EdgeOne 的几个特性很好地解决了我的需求:
其实 Cloudflare 也提供了类似服务,甚至免费,但在中国大陆地区的服务质量不是特别稳定,我所在的地区测试延迟很高,无法使用。
我的本地服务器环境为 Windows Server 2022,已使用 Docker 部署了我的博客,使用宿主机的 60023 端口。
腾讯云通过地址 https://api.edgeone.ai/ips 提供 EdgeOne 的节点 IP,并接收参数 version
和 area
来指定地区和 IPV4/IPV6。
为了能够动态地更新防火墙规则,我将其编写为一个 Python 脚本,放在计划任务中定期执行:
import requests
import subprocess
def get_ips(url):
try:
response = requests.get(url)
response.raise_for_status()
ip_list = response.text.strip().split('\n')
return sorted(ip_list) # 对获取的 IP 列表进行排序
except requests.RequestException:
return None
def read_previous_ips(filename):
try:
with open(filename, 'r') as file:
ip_list = file.read().strip().split('\n')
return sorted(ip_list)
except FileNotFoundError:
return None
def write_ips(filename, ips):
with open(filename, 'w') as file:
file.write('\n'.join(ips))
def delete_firewall_rules(group="@用户定义_EdgeOne"):
cmd = f"PowerShell -Command \"Remove-NetFirewallRule -Group '{group}'\""
subprocess.run(cmd, shell=True)
def add_firewall_rule(name, ips, protocol="TCP", direction="Inbound", action="ALLOW", group="@用户定义_EdgeOne"):
ips_str = '","'.join(ips)
cmd = f"PowerShell -Command \"New-NetFirewallRule -DisplayName '{name}' -Direction {direction} -Action {action.capitalize()} -Protocol {protocol} -RemoteAddress \"{ips_str}\" -Group '{group}'\""
subprocess.run(cmd, shell=True)
def main():
ip_versions = ['v4', 'v6']
areas = ['mainland-china', 'overseas']
changes_made = False
set_list = {}
for version in ip_versions:
for area in areas:
url = f"https://api.edgeone.ai/ips?version={version}&area={area}"
ips = get_ips(url)
if ips:
base_rule_name = f"{version}_{area}"
set_list[base_rule_name] = ips
filename = f"{base_rule_name}_ips.txt"
previous_ips = read_previous_ips(filename)
if ips != previous_ips:
changes_made = True
if changes_made:
delete_firewall_rules()
for base_rule_name, ips in set_list.items():
for i in range(0, len(ips), 200):
ip_group = ips[i:i + 200]
rule_name = f"EdgeOne_{base_rule_name}_Part_{i // 200 + 1}"
add_firewall_rule(rule_name, ip_group)
write_ips(f"{base_rule_name}_ips.txt", ips)
return changes_made
if __name__ == "__main__":
main()
该脚本从地址中读取节点地址,并分别添加一系列的规则,并且可以通过组进行筛选:
正确配置防火墙可以保证只有 EdgeOne 能访问到源站,以免被透过 EdgeOne 直接攻击源站服务器。
登录腾讯云控制台,进入到 站点列表 - EdgeOne - 控制台 页面,新增站点,并记录下站点 ID。
脚本源码可以查看 sqkkyzx/EdgeOneDynamicOrigin。
下载源码后,重命名 config.example.yaml
为 config.yaml
,并添加必要的配置。然后使用任务计划程序或 crontab 来执行脚本。
第一次运行时,脚本日志会输出查询到的公网 IPV6 地址,并新增一个本机主机名的源站组:
2024-12-11 19:00:03,649 - root - INFO - 地址 <240e:1****> Ping 测试通过,是公网地址。
2024-12-11 19:00:05,704 - root - INFO - 地址 <240e:2****> Ping 测试通过,是公网地址。
2024-12-11 19:00:07,861 - root - INFO - 地址 <2001:3****> Ping 测试失败。
2024-12-11 19:00:09,946 - root - INFO - 地址 <fd7a:4****> Ping 测试失败。
2024-12-11 19:00:09,947 - root - INFO - 本机公网 IPV6 地址为: ['240e:1****', '240e:2****']
2024-12-11 19:00:10,410 - root - INFO - 公网 IPV6 地址未发生变更,站点 zone-1***** 的源站组 **** 无需更新。
2024-12-11 19:00:10,907 - root - INFO - 公网 IPV6 地址未发生变更,站点 zone-2***** 的源站组 ***** 无需更新。
2024-12-11 19:00:11,545 - root - INFO - 解析记录 ***** 存在已过期的值 ***** , 正在删除。
如果配置了 DNS 相关配置,也会处理 DNS 解析。如果配置了钉钉机器人,则会发送通知到钉钉。
登录腾讯云控制台,进入到 站点列表 - EdgeOne - 控制台 页面,为站点添加子域名,回源到服务器主机名的源站组和对应服务的端口即可。
该方案与内网穿透相比,有一定局限性,比较依赖运营商是否开放 IPV6,其流量也很少,但它并不局限于内网穿透的 VPS 带宽。此外,仅用于 Web 服务时,价格相对可接受,并提供了一些基础防护和 CDN。总的来说,我的使用体验还不错。
Error parsing Mermaid diagram!
Cannot read properties of null (reading 'getBBox')