写在前面

为什么需要动态端口映射和动态域名解析?它们与内网穿透有什么区别?

当家庭宽带具备公网 IP 时,可以借助端口映射和动态域名解析(DDNS),通过 固定域名 + 端口号 远程访问家庭局域网中的服务,例如:

  • NAS;
  • 监控设备;
  • 局域网设备的 SSH 服务。

如果没有公网 IP,则需要考虑内网穿透等其他方案。内网穿透通常依赖中转服务器,例如自行在 VPS 上搭建服务,或使用花生壳等服务商提供的服务;部分服务的提速、绑定自有域名等功能需要额外付费。

方案选择:在有条件获取公网 IP 的情况下,可以优先考虑通过端口映射配合 DDNS,实现远程访问内网服务。

一、本地环境

  • 虚拟化平台:ESXi,运行 ROS 和 OpenWrt。
  • 网络条件:公网 IP。
  • 域名解析服务:托管至 DNSPod。

前提条件:本文方案需要公网 IP;没有公网 IP 时,需要采用内网穿透等其他方案。

二、所需软件

  • WinBox:用于配置 ROS。
  • SSH / SFTP 客户端:用于连接 OpenWrt、上传脚本及配置文件。

三、在 ROS 中配置动态端口映射

配置目的:即使公网 IP 发生变化,也能自动更新端口映射规则中的公网地址,保持公网端口与内网服务之间的映射。

1. 创建 NAT 规则

打开 WinBox,进入 IP → Firewall → NAT,添加一条 dstnat 规则:

  • 目标地址:查询并填入当前公网 IP。
  • 目标端口:填写映射后使用的公网端口。

例如:xxx.xxx.xxx.xxx:xx。

在 WinBox 中创建 NAT 规则

2. 配置内网服务地址与端口

切换到 Action 选项卡,设置以下内容:

  • Action:选择 dst-nat。
  • 地址和端口:填写需要映射的内网服务 IP 和端口,例如 192.168.1.yyy:yy。
  • 评论备注(Comment):为规则添加备注,供后续脚本定位使用。

至此,公网端口与内网服务之间的映射已经建立:

xxx.xxx.xxx.xxx:xx ↔ 192.168.1.yyy:yy

配置 NAT 规则的 Action 参数

为 NAT 规则添加评论备注

3. 添加公网 IP 更新脚本

普通家庭宽带即使具备公网 IP,地址也通常不是固定的。因此,建立端口映射后,还需要通过脚本自动更新规则中的公网 IP。

在 WinBox 中进入 System → Scripts,新建一个脚本:

  • 脚本名称:自定义,例如 scr1。
  • PPPoE 接口名称:根据实际配置填写,例如 pppoe-out1。
  • 防火墙规则备注:与需要更新的 NAT 规则保持一致,例如 comment1。

按照截图核对接口名称和规则备注,并配置脚本内容。

添加公网 IP 更新脚本

:global ipaddr [/ip address get [/ip address find interface=pppoe-out1] address]
:set ipaddr [:pick $ipaddr 0 ([len $ipaddr] -3)]
:global oldip [/ip firewall nat get [/ip firewall nat find comment="comment1"] dst-address]
:if ($ipaddr != $oldip) do={
    :log info [/ip firewall nat set [/ip firewall nat find comment="comment1"] dst-address=$ipaddr]
}

4. 配置计划任务

在 WinBox 中进入 System → Scheduler,新建计划任务:

  • 启动时间:设置为开机启动。
  • 执行间隔:根据实际需要设置,原文推荐 1~5 分钟。
  • 执行内容:调用上一步创建的脚本。

配置 ROS 计划任务

填入以下命令,并将 scr1 替换为实际脚本名称:

:execute "scr1"

完成并核对上述配置后,即可按设定间隔更新端口映射规则。下一步配置 DDNS。

四、利用 DNSPod 实现动态域名解析

域名在哪个平台购买并不重要,只要能将域名解析服务托管至 DNSPod 即可。本文仅介绍 DNSPod 的配置方法。

1. 添加初始 A 记录

注册并登录 DNSPod,将域名的解析服务器更换为 DNSPod 后,进入管理控制台,添加一条 A 记录:

  • 解析主域名:主机记录填写 @。
  • 解析子域名:主机记录填写需要使用的子域名。
  • 记录值:先填写一个占位 IP,例如 127.0.0.1。

务必先创建记录:后续脚本执行的是「更新」解析记录,而不是「添加」解析记录。

在 DNSPod 中添加初始 A 记录

2. 创建 API Token

进入 DNSPod 账号管理中心,创建密钥并添加 API Token。

妥善记录并保管密钥中的 ID 和 Token;按照原文说明,完整信息只会显示一次。

DNSPod 密钥管理界面

DNSPod API Token 配置界面

3. 下载客户端并修改配置

下载 ArDNSPod / DNSPod Shell 客户端:

解压后需要以下两个文件:

  • ddnspod.sh:执行 DDNS 更新的脚本。
  • dns.conf:配置文件。

使用文本编辑器修改 dns.conf:

  • arToken:填写上一步获得的 Token ID 和 Token,以英文逗号分隔。
  • arDdnsCheck:分别填写主域名和子域名。按照原文说明,如果直接解析主域名,则删去 "subdomain" 参数。
# 1. Combine your token ID and token together as follows
arToken="12345,7676f344eaeaea9074c123451234512d"

# 2. Place each domain you want to check as follows
# you can have multiple arDdnsCheck blocks
arDdnsCheck "test.org" "subdomain"

4. 上传并测试脚本

通过 SFTP 将 ddnspod.sh 和编辑后的 dns.conf 上传至 OpenWrt,例如放在 /root 目录下。

通过 SSH 执行以下命令,测试脚本:

sh /root/ddnspod.sh

如果执行成功,脚本会自动获取本机公网 IP,并通过 API 更新 DNSPod 中的域名解析记录。

下图展示了原先指向 127.0.0.1 的 @ 记录更新为公网 IP 的结果:

运行 DDNS 脚本后的输出

DNSPod 解析记录更新结果

5. 配置 crontab 定时更新

使用 crontab 定期执行脚本,自动检测公网 IP 并更新 DNS 记录,实现 DDNS。

编辑计划任务

执行以下命令:

crontab -e

如果提示选择文本编辑器,按需选择即可。加入以下内容:

# 每 5 分钟检测公网 IP 并更新 DNS 记录
*/5 * * * * sh /root/ddnspod.sh
  • */5:每 5 分钟执行一次,可按需调整。
  • /root/ddnspod.sh:脚本的绝对路径,请根据实际存放位置修改。

格式修正:原文中的计划任务表达式存在缺失字符及多余反斜杠,此处按照「每 5 分钟执行一次」的原意修正为上述格式。

保存并退出编辑器后,按实际系统的服务管理方式重启 cron。原文给出的命令为:

service cron restart

补充参考:安装 cron

系统差异:本文的脚本部署环境为 OpenWrt。以下 CentOS / Ubuntu 命令是原文附带的参考内容,不应直接套用于所有系统;安装命令、服务名称及管理方式应以实际系统为准。

CentOS(原文命令):

# 安装 cron
yum install vixie-cron
yum install crontabs

Ubuntu(原文命令):

# 安装 cron
apt-get install cron

补充参考:常用命令

# 启动服务
service cron start

# 检查状态
service cron status

# 重新启动服务
service cron restart

# 查询 cron 可用的命令
service cron

# 查看用户计划任务
crontab -l

# 编辑用户计划任务
crontab -e

完成上述配置后,动态端口映射和 DDNS 将按设定的时间间隔自动更新。此时可以通过以下方式访问内网服务:

域名:公网映射端口

五、结语

本文是对个人实机配置过程的一次整理记录,所用方法参考了互联网上的相关文章和项目。

当然,也有其他实现方案,例如通过阿里云域名管理直接对接 ROS 脚本,或使用其他免费的 DDNS 服务商。根据自己的环境和需求,选择适合的方案即可。

参考文章

  1. 利用 DNSPod 实现动态域名解析 DDNS
  2. ArDNSPod / DNSPod Shell

Chris · 2020-09-26