写在前面
为什么需要动态端口映射和动态域名解析?它们与内网穿透有什么区别?
当家庭宽带具备公网 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。

2. 配置内网服务地址与端口
切换到 Action 选项卡,设置以下内容:
- Action:选择
dst-nat。 - 地址和端口:填写需要映射的内网服务 IP 和端口,例如
192.168.1.yyy:yy。 - 评论备注(Comment):为规则添加备注,供后续脚本定位使用。
至此,公网端口与内网服务之间的映射已经建立:
xxx.xxx.xxx.xxx:xx ↔ 192.168.1.yyy:yy


3. 添加公网 IP 更新脚本
普通家庭宽带即使具备公网 IP,地址也通常不是固定的。因此,建立端口映射后,还需要通过脚本自动更新规则中的公网 IP。
在 WinBox 中进入 System → Scripts,新建一个脚本:
- 脚本名称:自定义,例如
scr1。 - PPPoE 接口名称:根据实际配置填写,例如
pppoe-out1。 - 防火墙规则备注:与需要更新的 NAT 规则保持一致,例如
comment1。
按照截图核对接口名称和规则备注,并配置脚本内容。

: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 分钟。
- 执行内容:调用上一步创建的脚本。

填入以下命令,并将 scr1 替换为实际脚本名称:
:execute "scr1"
完成并核对上述配置后,即可按设定间隔更新端口映射规则。下一步配置 DDNS。
四、利用 DNSPod 实现动态域名解析
域名在哪个平台购买并不重要,只要能将域名解析服务托管至 DNSPod 即可。本文仅介绍 DNSPod 的配置方法。
1. 添加初始 A 记录
注册并登录 DNSPod,将域名的解析服务器更换为 DNSPod 后,进入管理控制台,添加一条 A 记录:
- 解析主域名:主机记录填写
@。 - 解析子域名:主机记录填写需要使用的子域名。
- 记录值:先填写一个占位 IP,例如
127.0.0.1。
务必先创建记录:后续脚本执行的是「更新」解析记录,而不是「添加」解析记录。

2. 创建 API Token
进入 DNSPod 账号管理中心,创建密钥并添加 API Token。
妥善记录并保管密钥中的 ID 和 Token;按照原文说明,完整信息只会显示一次。


3. 下载客户端并修改配置
下载 ArDNSPod / DNSPod Shell 客户端:
- 原项目地址(原文已划线):
https://github.com/imki911/ArDNSPod - 原文提供的替代项目:rehiy/dnspod-shell,基于 DNSPod 用户 API 的纯 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 的结果:


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 服务商。根据自己的环境和需求,选择适合的方案即可。
参考文章
Chris · 2020-09-26