前段时间我在另一篇文章中提到了我购置了一款斐讯N1盒子并刷入了Armbian系统。点击这里查看相关文章

这台N1按照计划是放到移动免费送的宽带(没有公网IP,只有100.64开头的运营商级NAT)下面当成个小号国内VPS玩的,但是宽带接入到家里一栋老屋了,所以需要做一下内网穿透。

从充分利用网络带宽的角度来说,自然是UDP打洞实现的内网穿透具有更好的性能,但是出于稳定性考虑,我决定先部署一个frp的客户端将SSH端口转发到腾讯云学生机,保证UDP打洞出问题的时候可以修复。

接下来的部分会简单介绍一下折腾frpZerotier的经历,以及使用体验。

利用frp实现端口转发

frp很多人都了解,是一个用于内网穿透的高性能的反向代理应用,简单点说就是可以把NAT后面的某台机器的端口转发到公网IP上去,类似ngrok或者花生壳内网版,好处是可以自建。

frp的官方中文文档写的不错,而且也有很多网友分享了部署的教程,所以这里就不再赘述安装过程和配置文件的格式,只简单提供一个适用于Armbian的systemd启动脚本。

[Unit]
Description=frpc
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/frpc -c /usr/local/etc/frpc.ini
Restart=always

[Install]
WantedBy=multi-user.target

把上述内容放到/etc/systemd/system/frpc.service文件中,然后执行systemctl enable frpc,然后frp就会在N1盒子开机连接网络后自动启动了。

一开始我选择用熟悉的supervisor来自动启动frpc,但是很快发现了问题,由于frpc开始时会进行联网,如果启动时没有配置好网络那么就会导致启动失败,而supervisor又没有延时启动的参数,因此选择了可以指定启动顺序的systemd,事实上这也是Debian系统推荐的方式。

上文配置文件中的After=network-online.target就是在网络连接成功后启动,根据我的测试,可以稳定启动frpc。

利用Zerotier通过UDP打洞实现内网穿透

UDP打洞是一种NAT穿透技术,与上面frp的区别在于,frp的转发模式本质是通过具有公网IP的服务器M来进行流量转发(frp也提供xtcp模式来进行NAT穿透,但是成功率太低,效果不佳),这样如果服务器M的带宽有限,就会成为传输时的瓶颈,无法有效利用全部带宽。

Zerotier就是利用UDP打洞来实现内网穿透的工具,而且相比其他工具成功率更高、部署更简单。

注册账号

要使用Zerotier要先去官方网站创建一个账号,直接选择Free套餐即可,可以提供100台以内设备的内网穿透,完全够用了。

之后去网络管理页面创建一个网络并记住NetworkID。

网络管理界面可以配置很多东西,但是这里只介绍需要用到的部分,就是NetworkID和下面的Members。

NetworkID是在连入新设备时需要用到的标识符,每个设备连接这个虚拟的局域网时都要输入这个ID。

Members则是连入网络的设备列表,按照默认的设定,当有一个新设备接入网络时,用户需要在这个页面进行授权

安装Zerotier客户端

安装部分可以直接参考其下载页面,提供包括Windows、常见Linux发行版、OpenWrt、macOS、Android、iOS甚至QNAP、群晖等多个系统的客户端。

Armbian可以直接使用提供的一键脚本来进行安装:

curl -s 'https://pgp.mit.edu/pks/lookup?op=get&search=0x1657198823E52A61' | gpg --import && \
if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z" | sudo bash; fi

在Armbian上,一键脚本的基本功能就是添加一个apt源,然后从源安装名为zerotier-one的程序。

之后只需要执行zerotier-cli join <NetworkID>,然后再去上文提到的网络管理页面授权连接并分配IP地址就可以将这个设备接入网络了。

这样再用另一个设备接入这个网络时,即使两个设备都没有公网IP,他们也能用虚拟局域网的IP互相访问了。

部署中间服务器Moon

这里要简单提一下UDP打洞的原理,UDP打洞的本质是让NAT后面的机器A和B先连接一个有公网IP的中间服务器,然后中间服务器经过一番操作之后让A和B直接互联,这样之后的数据传输就是A和B之间直接传输,不再通过中间服务器。

但是出于节省资源和增强健壮性的角度,A和B服务器直接打出来的「洞」并不是永久的,而是维持一段时间后释放,下次连接时重新打洞。这样就带来一个问题,Zerotier是一款国外的项目,他提供的中间服务器到大陆的网络状况并不好,有很高的延迟,并且很可能丢包,这就导致我们每次「打洞」都有很高的延迟。

以我的网络环境进行的测试中,第一次「打洞」有接近500ms的延迟,之后延迟降低到100ms以下,直到这个「洞」被释放。

为了解决这个问题,Zerotier提供了一个moons的概念,官方文档中提供了详细的解释和配置方法。

这篇博客文章提供了一份中文的教程,有兴趣的读者可以按此操作。

我的中间服务器部署在腾讯云,对三网都有良好的延迟和极低的丢包,因此在部署成功后,「打洞」的第一个数据包延迟降低到了不到200ms,同时由于丢包较低,打洞成功率也有所上升。

一些简单的网络测试

事实上Zerotier的打洞效果好的令我惊讶,我的网络环境A是上行20M下行100M的电信网络,B则是移动赠送的50M上下行对等移动网络。

晚高峰时段,在两边都开启bbr的情况下,互相下载文件可以跑到网络峰值的60%~70%。
电信拖移动能跑到3MB/s,反过来则是1.4MB/s左右。
延迟的话「打洞」完成之后稳定在90ms,丢包率在8%左右。

顺便吐槽一下,一开始看到90ms的延迟我还以为打洞出了问题,结果直接从移动ping了一下电信的公网IP(我的电信网络环境是有公网IP的,但是我并没有在路由器设置端口转发,因此测试效果仍然是打洞的效果),发现延迟也在90ms上下,通过traceroute命令追踪路由发现数据包先从隔壁的H省进入移动骨干网,然后进入电信骨干,再从另一个方向隔壁的S省回到本地电信,难怪会有这么高的延迟orz

同样,8%也是晚高峰电信和移动互联本身的延迟。换而言之,Zerotier的打洞非常成功,延迟和丢包率基本都和公网差距不大,但是由于本身移动和电信晚高峰时段的互联效果较差,因此效果并没有想象中完美。从延迟的角度,本地电信到香港阿里云服务器的延迟尚在50ms以下,到洛杉矶的CN2服务器也不过150ms,然而与本地移动互联延迟竟然高达90ms,国内ISP互联还是任重道远啊。


本文由 sandtears 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

楼主残忍的关闭了评论