用 FRP 内网穿透,随时随地远程连接

谁都不想天天带着厚重的游戏本出去,更何况某些高性能的服务器或者台式机等设备根本带不出去,于是有了远程桌面和 SSH 之类功能,前者在远程设备中连接另一台 Windows 电脑的桌面,后者则访问另一台电脑的终端命令行。

但是,中国的网络环境大家都懂的,大部分电脑都没有公网 IP,对于既有移动需求又有远程桌面需求的电脑来说,IP 也时常会变换。能不能有一个有固定公网 IP 的云主机,来作为中转,将流量转到被连接的主机上呢?

于是我们有了 FRP。FRP 可以进行内网穿透,具体来讲,就是我们上面所说的事情。

fatedier/frp

FRP 原理图

FRP 由两部分组成,分别是服务端和客户端,前者是有公网 IP 的那台机器,后者是由于各种原因需要被穿透的那台机器。

在看下面的内容之前,建议先了解一下 端口号 的概念。

搭建 FRP 服务端

我们需要一台有固定公网 IP 的机器来搭建 FRP,常为云主机。建议选择中国大陆网络连接比较顺畅的服务器,以保证较低的延迟。

首先从 FRP release 页面下载适合你服务端机器的包,一般是 amd64,Linux 还是 Windows 依你服务器端的系统决定。解压,然后将它传到你的服务器上;如果你对命令行足够熟悉,也可以直接用 wget 命令在服务器上下载解压。

然后,进入 FRP 的路径,修改 frps.ini,基础的结构如下:

ini
1
2
3
4
5
6
7
8
[common]
bind_port = xxxx # 服务端与客户端之间通信所用的端口
dashboard_port = xxxx # 网页控制台的端口号,你没有域名的话可以使用 “服务器 ip: 这个端口号” 来访问控制台
token = xxxxx # 客户端连接到服务端的密码
dashboard_user = xxxx # 网页控制台的用户名
dashboard_pwd = xxxx # 网页控制台的密码
vhost_http_port = xxxx # HTTP 协议端口
vhost_https_port = xxxx # HTTPS 协议端口

server_port 是服务端与客户端通信使用的端口,而下一部分提到的 remote_port 是外界连接至服务端的哪个端口,相当于连接到客户端的 local_port。

按需设置即可,注意端口不要冲突了。这些数字可能都会用到,也别忘了。完成之后,输入命令 ./frps -s frps.ini 来启动服务端。推荐使用 nohup 命令来实现后台运行:nohup ./frps -s frps.ini $。不会有人用 Windows Server 吧?

搭建完成之后,访问 “你的服务器 IP: 控制台端口号” 来访问网页控制台,并用先前设置的控制台用户名和密码登录,这里你就可以看到你的 FRP 服务器信息了。

此外,你也可以使用 Sakura Frp,它是预先搭建好的一系列 FRP 服务器,你可以免费使用,但它的带宽等有一定的限制,如果想追求更好的体验,最好还是自行使用国内的服务器搭建。

搭建 FRP 客户端

由客户端决定要和 FRP 服务端建立几个连接,各个连接分别转发哪个端口,以及应该如何转发。

在将任何东西暴露于公网之前,我建议:

  • 做好适当的防护措施,防止攻击;
  • 先在局域网下测试连接通过,排除客户端本身设置问题造成的麻烦。

仍然是从上面的 release 页面下载对应于你客户端机器系统的压缩包,客户端和服务端是同包的。解压之后编辑 frpc.ini,基本结构如下:

ini
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[common]
server_addr = xxx # 你服务端的地址,可以用域名或者 IP 地址,这里不加端口号。
server_port = xxx # 服务端与客户端通信所用的端口号
token = xxx # 客户端连接到服务端的密码

[xxx] # 这一套配置文件的名称,可以自定义,一套配置文件建立一个连接,一个 ini 可以有多套
type = tcp # 通信所用的协议,支持 TCP、UDP、HTTP、HTTPS 等协议的转发,要与实际通信协议配套
local_ip = 127.0.0.1 # 本地需要暴露到互联网上的 IP 地址,理论上也可以是同一个局域网的,本机的话就是 127.0.0.1 或者 localhost
local_port = xxx # 本地需要暴露到互联网上的端口号
remote_port = xxx # 服务端可以将什么端口映射为你本地的端口
use_compression = xxx # 是否启用压缩,值为 true 或者 false,启用则占用两边 CPU 资源
use_encryption = xxx # 是否加密,同上

更详细的配置可以参考文末附录的官方文档。然后输入命令 ./frpc -c frpc.ini,就可以启动客户端服务了。

你可以打开上述的服务端网页控制台,来检查一下连接是否成功。

Windows 系统的特别提示

鉴于很多人使用的是 Windows 系统,这里特别提醒一下:需要使用 cmd 或者 PowerShell 等终端来启动,不能直接双击 frpc.exe,并且命令窗口关闭之后就会停止运行。

那么怎么去除碍眼的命令行,还让它一直后台运行呢?少数派的文章中提出,可以写一个 batch 脚本,来实现这个效果:

bat
1
2
3
4
5
6
7
@echo off
if "%1" == "h" goto begin
mshta vbscript:createobject("wscript.shell").run("""%~nx0""h",0)(window.close)&&exit
:begin
cd X:\xxx rem 这个路径改为 frpc.exe 的位置
frpc -c frpc.ini
exit

如果你没有 Visual Studio Code 等代码编辑器,你也可以将这段内容复制到记事本里,另存为一个文本文档,然后将文件扩展名改成. bat,是一样的效果。

现在,双击这个 bat 文件,就可以启动后台服务了;在任务管理器中找到 frpc.exe,结束它,就能将它关闭。你还可以使用 “计划任务” 功能实现 FRP 的开机启动。至于 Linux 用户,这些步骤大同小异,请参考上一节的 nohup 命令。

远程连接 WSL 2 子系统

正如我开头提到的,相信很多人都拥有高性能但不太好移动的计算机,而为了方便日常生产生活,这台计算机常装有 Windows 系统。有些工作实在是没必要用远程桌面完成,只需要 SSH 连接终端就可以了,这时使用 SSH 连接 WSL 子系统内的 Linux bash 终端,就可以随时轻易利用强大的算力了。下面以 Windows 10 21H1 上的 Ubuntu 20.04.2 LTS 为例。

需要特别注意的是,WSL2 系统本身是并不能直接 SSH 连接的。要解决这个问题,首先要重装一个 “正常的”OpenSSH”:

bash
1
2
sudo apt-get remove openssh-server
sudo apt-get install openssh-server

然后还需要编辑一下 sshd_config 文件,使其允许使用密码接入 SSH,当然如果你能够把所有设备的公钥全都加进去,倒也可以不用用户名和密码…… 毕竟这是要暴露到公网上的东西,我甚至更推荐使用 RSA 公钥验证。

如果你需要密码登录,则用 sudo 提权后使用文本编辑器编辑 /etc/ssh/sshd_config 文件。我这里推荐使用 Visual Studio Code(前面加 code 或者 code-insiders,需要 Windows 宿主系统上装有 vscode),或者 GNU Nano(前面加 nano),当然如果你是大佬也可以用 Vim 之类的工具。打开之后,将 PasswordAuthentication 后面的 no 改为 yes 即可。

然后下载 Linux AMD64 版本的 FRP 包,修改 frpc.ini 如下:

ini
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[common] # 这个和上面同理
server_addr = xxx
server_port = xxx
token = xxx

[WSL_ssh] # 这个名称可以自定义
type = tcp # SSH 协议建立在 TCP 的基础上,所以填 TCP
local_ip = 127.0.0.1
local_port = 22 # 本地 SSH 端口默认为 22,当然你可以改,也建议改一下,记得同步修改 SSH 配置
remote_port = xxxx # 服务端映射的端口

运行服务,你就可以远程连接到 WSL 2 了,注意端口号的变化。使用命令 ssh -oPort=remote_port user@server_addr 来连接客户端的 SSH。


ref.

使用 frp 进行内网穿透 - 少数派 (sspai.com)

文档 | frp (gofrp.org)

使用 ssh 工具连接到 ubuntu on windows(wsl) - 简书 (jianshu.com)