用frp弥补zerotier的不足

大部分情况下,自建planet/moon后,zerotier表现良好。但在某些特殊时期(比如每年的6月),运营商可能会采用比较激进的QoS策略,对基于UDP协议的Zerotier很不友好,具体表现在:

1、客户机之间能Ping通,也实现了直连(打洞),Ping值很低,但频频出现丢包;

2、客户机之间Ping值变大,直连(打洞)无法成功,或需要很长时间才能成功;

3、客户机之间传输数据的带宽显著降低。

以上问题,当客户机之间的物理距离拉长(比如跨省)或跨运营商(比如,客户机A在电信,客户机B在移动)时表现得尤为明显。

Zerotier采用随机端口的UDP协议传输数据。虽然UDP对于穿透NAT具有得天独厚的优势,但从本质上说,这类随机端口的UDP数据包总是被认为“优先级”更低的,关键时刻很容易被“优先抛弃”。

那么,能不能改用TCP协议呢?对于Zerotier来说,不能。因为NAT很容易阻止TCP的3次握手,导致TCP协议在穿透方面毫无优势。所以,我们面临的情况是:UDP穿透打洞容易,但优先级低不稳定;TCP优先级高非常稳定,但穿透打洞很困难

所以,理想的解决方案是,用其他方式来实现TCP转发,但求稳定,不求直连。它就是鼎鼎大名的frp。Zerotier+UDP可以与frp+TCP互补,一个不行的时候就用另一个。

服务端frps配置

首先必须拥有一台公网服务器。本文以ubuntu server为例。

frp默认服务端口:7000

frp dashboard默认端口:7500

确保云服务器的网页端防火墙以及服务器自己的ufw都放行了上述两个端口。

此外,还需要放行用于客户端接入的端口。假设我们使用30001-30010这10个端口来对应不同的frp客户端,那么也同样放行它们。

到这里下载frp的最新版本:https://github.com/fatedier/frp/releases/,其中,frp_0.xx.0_linux_amd64.tar.gz是用于ubuntu的。

将它解压缩,并把frps二进制文件、frps.toml配置文件复制到\opt\frp\(目录随意,以此为例)。

赋予frps可执行权限:

chmod +x \opt\frp\frps

编辑frps.toml文件。

[common]
bind_port = 7000
kcp_bind_port = 0
auth.method = "token"
auth.token  = "YOUR_AUTH_TOKEN"
dashboard_port = 7500
dashboard_user = "admin"
dashboard_pwd  = "YOUR_ADMIN_PASSWORD"
tls_only = true

注意大写部分改成你自己的。

之后注册systemd服务,在\etc\systemd\system\目录下,创建frps.service文件:

[Unit]
Description=frp server
After=network.target

[Service]
User=root
ExecStart=/opt/frp/frps -c /opt/frp/frps.toml
Restart=always

[Install]
WantedBy=multi-user.target

然后更新daemon,启动服务:

systemctl daemon-reload
systemctl enable frps
systemctl start frps

为确保服务运行正常,可以检查一下状态:

systemctl status frps

如果是绿色监听状态,服务端就配置好了。

客户端frpc配置

客户端配置以Windows 11为例。

到这里下载nssm:https://github.com/kirillkovalenko/nssm,它用来注册windows系统服务。

到这里下载frp的最新版本:https://github.com/fatedier/frp/releases/,其中,frp_0.xx.0_windows_amd64.zip是用于Windows的。注意,在解压缩frp_0.xx.0_windows_amd64.zip的时候,病毒防火墙可能会报警,因为frps.exe经常被黑客用来做后门,所以Windows默认会杀掉它。其实不要紧,因为我们不用frps.exe,只需要用到其中的frpc.exe和frpc.toml。

将frpc.exe、frpc.toml复制到c:\frpc目录(任意目录,以此为例)。

将win64版本的nssm.exe复制到c:\nssm目录(任意目录,以此为例)。

修改c:\frpc\frpc.toml文件:

[common]
server_addr = "YOUR_FRPS_SERVER_IP"
server_port = 7000
auth.method = "token"
auth.token  = "YOUR_AUTH_TOKEN" #注意必须与frps上设置的完全一致
tls_enable  = true
transport.protocol = "tcp"

[rdp-client01]  #这里不同的frpc机器得是不同的名称
type = "tcp"
local_ip = "127.0.0.1"
local_port = 3389     #假设要穿透出去的是远程桌面服务
remote_port = 30001   #前文已经说明,frps的防火墙要开放对应端口

注意,大写的部分要改成你的。

这一段的意思是,让frpc客户机,凭auth.token与frps握手成功,并告诉frps:我将要使用你的remote_port来映射我的local_port。所以这里对于初次使用frp的用户会是一个小小的trick:frps上开放哪个端口竟然是frpc决定的!

以管理员身份运行cmd,定位到c:\nssm,然后安装frpc服务:

cd /d c:\nssm
nssm install frpc

nssm会弹出一个窗口。第一个配置页是服务的基本信息:可执行程序的路径、启动目录、运行参数。它们分别是:

路径:C:\frpc\frpc.exe
启动目录:C:\frpc
参数:-c C:\frpc\frpc.toml

为了便于调试,建议切换到I/O配置页,把3个日志文件设置一下:

c:\frpc\logs\frpc_in.txt
c:\frpc\logs\frpc_out.txt
c:\frpc\logs\frpc_err.txt

确定,服务安装成功。

可以运行services.msc查看frpc服务的运行状态。确保它处于运行状态。c:\frpc\logs\中的日志文件可以看出当前服务执行是否正常。由于frpc端是“主动”连接frps,所以frpc端无需设置防火墙例外。

此时不出意外的话,用另一台电脑访问YOUR_FRPS_SERVER_IP:30001,即可连接到frpc的远程桌面了。

更多的客户端frpc配置

说是frpc客户端,在真正使用起来它其实是“服务端”。假设frps是S,frpc是C,日常使用的其他真正的客户端是A,那么上述配置之后,是A通过S中转连接到C提供的服务(比如3389)。

实际应用中,A可能是到处移动的笔记本,而C可能不止1台,比如,办公室的台式机是C1,家里的台式机是C2……如果已经配置好了一台C,想要再增加1台怎么办呢?

步骤与第一台C大同小异,唯一需要注意的地方是frpc.toml需要修改:

[common]
server_addr = "YOUR_FRPS_SERVER_IP"
server_port = 7000
auth.method = "token"
auth.token = "YOUR_AUTH_TOKEN"
tls_enable = true
transport.protocol = "tcp"

[rdp-client02] #这里不同的C机器是不同的名称
type = "tcp"
local_ip = "127.0.0.1"
local_port = 3389
remote_port = 30002 #不同的C对应不同的端口

注意,不同的C用到的所有remote_port,都要在S上的防火墙中放行。

文件下载

如果你访问Github存在困难,文中用到的所有工具可以在这里下载。