前段时间我在另一篇文章中提到了我购置了一款斐讯 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,可自由转载、引用,但需署名作者且注明文章出处。

楼主残忍的关闭了评论