关于NAS远程访问
因为是在外地工作,在这边只租了一个小单间,一台 NAS 如果是 7*24 小时开机的话,放房间里那炒豆子的声音我确实有些受不了。
想到家里有动态公网 IPv4,我还在路由器里做好了 DDNS,于是去年年底的时候,我将 NAS 带回了家。为了给自己一个清净,舍弃了千兆内网传输。
但在家装好 NAS 之后,外网访问测试时,又发现了很多问题,其中最让我难受的是在测试途中,我发现 Windows 自带的资源管理器,无法自定义 SMB 的访问端口。
也就是说,如果 NAS 放在远端,使用公网 IP 地址进行 SMB 访问的话,需要开启 445 端口,但 445 端口开放,就意味着几乎是向勒索病毒敞开了大门,毫无安全性可言。
在网上寻求解决办法,于是在知乎上找到了一篇提问:Windows 10 如何修改 SMB 的默认端口(445)?
里边有些回答提到了可以通过端口转发的方式来访问非 445 端口的 SMB 服务。
打个比方,如下命令:
netsh interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=445 connectaddress=70.70.70.70 connectport=11451
如果本地资源管理器访问 \\127.0.0.1 ,其实就是访问的 127.0.0.1 这个 IP 的 445 端口,127.0.0.1 这个 IP 指的是本机,也就是在访问本机的 SMB 服务。
上方命令执行后访问 IPv4 地址 127.0.0.1:445 后,会被转发到 70.70.70.70:11451。当然这个 70.70.70.70 地址只是我随意编的,这个地址和后面的 11451 端口需要替换为你 SMB 服务器的公网 IP 地址和修改后的 SMB 端口。
如此,实现了用 Windows 资源管理器远程访问非 445 端口的 SMB 服务。
如果还是无法访问,需要检查服务中 Ip Helper 服务是否开启。
附上一段简短的端口转发笔记:
# 添加规则
netsh interface portproxy add 转发类型 listenaddress=本机ip(127.0.0.1) listenport=监听端口(5700) connectaddress=目标设备ip(192.168.10.10) connectport=转发端口(5700)
netsh interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=5700 connectaddress=192.168.10.10 connectport=5700
# 修改规则(只需要把 add 改为 set)
netsh interface portproxy set v4tov4 listenaddress=127.0.0.1 listenport=5700 connectaddress=192.168.10.10 connectport=5700
# 删除规则
netsh interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=5700
# 查看规则
netsh interface portproxy show v4tov4
参考 2:Netsh 命令语法、上下文和格式设置 | Microsoft Learn
但这么做有两个弊端,也是我不太乐意用这个办法的原因。
- 端口转发设置的目标 IP 只能是 IP 地址,不能为域名
- 访问方自己不能是个 SMB 服务器
这两点对于我而言都是难以接受的。
首先第一点,家里的公网 IPv4 是动态的,必须要做 DDNS 才能无感使用,端口转发不能设置域名只能设置 IP,这对我而言略显麻烦。不过这个问题是有解决办法的,详见:Windows 10 如何修改 SMB 的默认端口(445)? - greader的回答。
其实就是创建一个脚本,定期自动执行一次,脚本内容则是通过 Ping 的方式获取该域名的 IP 地址,然后自动替换上方端口转发中的目标设备 IP,然后自动执行端口转发规则修改。
而第二点就比较致命了,我更希望的是我每一个设备都能互相之间传输文件,如果说我正在使用的这台电脑,为了能远程访问家里的 NAS,我就要关掉这台电脑的 SMB 服务,因为上方命令执行后需要访问的 IP 是 127.0.0.1 这个地址,如果本机是个 SMB 服务器的话会直接访问到本机的 SMB 目录,但如果将上面命令里的 127.0.0.1 换成了别的 IP,又会出现各种无法访问的问题。
当然,在写这篇文章的时候我发现这个问题也是可以解决的,参考:windows通过任意端口访问samba - 知乎 (zhihu.com)。说白了就是创建一个虚拟网卡、虚拟地址来替代这个 127.0.0.1。
其实这篇文章写到这里,关于 “在 SMB 服务器有外网的情况下如何使用 Windows 远程访问这个 SMB 服务器并且不通过 445 端口” 的问题,已经有了完整的解决方法:
首先将 SMB 服务器域名映射出去,不要使用 445 端口,映射一个别的端口出去,在访问方 Windows 系统中创建一个虚拟网卡并设置好 IP,然后执行端口转发命令。如果是动态的公网 IP,就直接使用上面提到的那个通过 Ping 的方式获取 IP 的脚本,改好脚本中的 IP 和域名,设置好定期执行就行了。
但是我没有用这种方式,无法写出体验究竟如何。这篇文章也不是教学,只是一个记录而已,就不详细说明了,但其实贴在上面的那些连接里的内容已经写得很详细了。
接下来就说一下我自己在用的方法,就是利用 ZeroTier 创建一个虚拟局域网,然后直接在这个虚拟局域网里进行操作。
当然这个办法很多人都不太喜欢使用,主要还是因为 ZeroTier 的节点服务器均在国外,如果两个设备之间建立连接失败,那么数据就需要过这个在国外的服务器,那么传输速度影响是非常大的,20KB/s 都算好的了,很大部分时间基本上是处于无法连接的状态。虽然创建一个在国内的 Moon 服务器可能会稍微改善一下速度,但还是有问题在于 ZeroTier 的安卓客户端和 iOS 客户端是没有加入 Moon 服务器的功能的。
不过这对我而言影响都不大,首先我自己有 Moon 服务器,其次我的 ZeroTier 是挂在 OpenWRT 下的,所以我的手机和平板只要连上了这个 OpenWRT 的网络环境,并且在 OpenWRT 的管理界面里勾选了“自动允许客户端 NAT”,那么就不需要安装 ZeroTier 客户端。
那么,使用这个方式首先就会遇到一个大问题。
首先是群晖貌似在某一个版本更新之后,就无法安装 ZeroTier 套件了,看网上基本都是通过 Docker 安装 ZeroTier 的方式解决这个问题的,但我的群晖 NAS 是最便宜的那款双盘位的 DS220j,内存只有 512M,套件中直接就没有 Docker 功能,就算有,可能这个内存大小根本带不动 Docker。
那么就只能用我上面提到的把 ZeroTier 挂在 OpenWRT 里的办法了。
于是我入手了一台 R2S,这个软路由给我的第一感觉就是,小巧,精致。在上面装好了 iStoreOS,iStoreOS 估计是 R2S 适配最好的一个 OpenWRT 了吧?
首先把这台 R2S 接在路由或光猫下面,让这台 R2S 能连上互联网,然后将 NAS 接在这台 R2S 上,并且设置好固定 IP。在 OpenWRT 里配置好了 ZeroTier 后记得勾选上“自动允许客户端 NAT”,再装一个 Socat,Socat 其实就是个端口映射工具,将 SMB 的 445 端口映射出去,因为这个 445 其实就相当于是在内网进行的映射,没有放到公网上去,所以是没有问题的。
当然其实也完全不需要进行端口映射,在 ZeroTier 中设置一个 Managed Routes,例如这台 OpenWRT 的 ZeroTier 地址是 172.25.1.30,挂在下面的 NAS 内网地址是 192.168.60.10 时这样设置:

192.168.60.0/24 即 NAS 所在的网段,172.25.1.30 即 ZeroTier 给这个 OpenWRT 分配的 IP 地址。
就相当于是访问 192.168.60.* 这个网段时,通过 172.25.1.30 这个网关进行。于是在远端进行访问的设备,只要 IP 不是在 192.168.60.* 这个网段,就能直接输入 192.168.60.10 访问到 NAS,并且不需要端口映射。这也是我认为用 ZeroTier 更方便的原因了。
其实这篇博客在6月底之前就已经完成了,但因为保存了好几份,最初只写了几段的那个版本被我上传到了 NAS 里,然后又复制了一份放在电脑上,电脑上的这一份文档写完了,忘了覆盖 NAS 里的那个旧备份,隔天把电脑上的这一份给删掉了,于是最终的结果就是重写。
总之吸取教训,看清楚了再删。
这篇文章很多细节都没有写清楚,因为这只是一篇记录而已,不算教程。 NAS 远程访问的这个问题算是结束了,不过说实话我还是更喜欢直接内网访问,主要是传输速度够快,但没这个条件啊。