在二级路由下用树莓派和 frp 折腾内网穿透
在二级路由下用树莓派和 frp 折腾内网穿透
丁俊尧背景
买一个树莓派做开发,一直是我想做的事情。只可惜我一直没钱。直到今年双十一,我咬了咬牙,终于买了树莓派。
其实我当时买树莓派有一个直接原因,就是希望开发云打印项目。令人失望的是,由于驱动问题,办公室里面三台打印机,只有一台能连上树莓派,偏偏那一台是性能最差的那台。在这方面,树莓派还不如办公室里面一台我带来的十一年前的笔记本电脑——三台打印机均能够顺利连接。于是,这台树莓派一直插着电放在创业园的办公室里面吃灰。
当然,我要是想执行什么命令的话,拿着电脑到创业园,连上办公室的网络,开 SSH 连树莓派就可以了——甚至不用拿电脑,用那台十一年前的电脑就可以了。我很长时间都是这样,但是这个方法的弊端也很明显:你如果忘记带书和资料的话,就要在宿舍和办公室之间跑上一来回。虽然创业园离宿舍并不远,但是我的宿舍在六楼啊。这就让我有了远程操作树莓派的想法。
众所周知,运营商分配给用户的 IP 是变化的,这种情况下就需要 DDNS,就是通过客户端将域名指向你现在的 IP 地址,动态检测变化。办公室的路由器是 TP-LINK 的,虽说不是智能路由器,不过也有 DDNS。按理说,只要设置好 DDNS 和端口转发,就不成问题了。但是我发现行不通。后来我知道 DDNS 实现的前提是路由器有公网 IP,而不巧的是办公室里面没有公网 IP,处在校园网内,属于二级路由……
我在阿里云上用学生权益买了一年的入门级 ECS,与此同时买了花生壳的内网穿透服务。虽然经过测试,花生壳能够在树莓派上运行并进行内网穿透,但是我购买的价位的功能实在太有限了,对于学生来说还是钱要紧。
这时候我自然而然地想到了那台 ECS。ECS 拥有固定的公网 IP,完全可以通过它来实现内网穿透啊。我本来不需要再花钱的。
说到内网穿透,我就想到了……ngrok。但是 ngrok 第二版不再开源,第一版不适合生产环境,而且经测试,无法运行。不管是我的操作有误还是本来就不行,那个没法放在后台的界面也是一个问题。
正当我失望之时,另一个内网穿透的工具进入了我的视线——frp。经简单测试,frp 对于我来说是可以运行的。
不过这里面的“测试”进行的时候,我对远程操作树莓派的需求没那么强烈,所以就暂时搁在一边了。直到最近气温骤降,我又因为急刹车导致手部受伤,实在无法在办公室停留太长时间(虽然办公室有空调,但电费是我出的啊),于是这个计划就又提上了日程。
实现这个计划足足花了我三天的时间。期间查了大量的资料,由于误操作重装了三次系统。不过最后总算成功了。我就把成功的操作说一下吧。
网络结构
首先,我在此之前就通过路由器的 IP - MAC
绑定为树莓派和笔记本电脑分配了固定的 IP。路由器是
192.168.1.1
,树莓派是
192.168.1.120
,笔记本电脑是
192.168.1.121
。于是我们得出以下网络图:
以下假定服务器的地址是 example.com
,且该域名可控。
下载
接下来到 GitHub 上下载 frp
的发行版本。下载时看好对应的平台。ECS 对应的是
linux_amd64
,树莓派对应的是
linux_arm
(居然不是 64 位的……)。
下载的时候,复制对应的文件的链接,进入一个方便的目录,然后执行(从下面开始,shell
命令、脚本中被 $()
包裹的语句(包含
$()
)替换成所述的部分):
1 | wget $(链接) |
稍后你就会看到目录里面多了一个对应的文件。
然后解压:
1 | tar -xzv -f $(frp 压缩包路径) -C $(要解压到的路径(不含 frp 文件夹本身)) |
之后你会在对应的目录中看到以 frp 开头的文件夹。由于名字太长不好记,我们最好把文件夹改一下名字:
1 | mv $(frp 文件夹路径) $(改名后的 frp 文件夹路径) |
最终,我在 ECS 上解压到了 /root/frps
中,在树莓派上解压到了 /home/pi/frpc
中。
配置
我们在这里的目标就是能够在外网连接 SSH。我们可以参考文档来对 frp 进行配置。frp 的一个好处是官方文档有中文版的。
编辑 ECS 上的 frps.ini
文件,这里面的路径是
/root/frps/frps.ini
:
1 | [common] |
另外,确保以上提到的这些端口号没有被其他应用占用。
然后编辑树莓派上的 frpc.ini
文件:
1 | [common] |
阿里云的 ECS
中需要对网络安全组进行设置,允许出入站方向的端口。比如在上面的例子中,我们要允许出入站方向
TCP 连接6000
、6022
的端口。
阿里云的网络安全组默认是允许所有出站端口的,所以这种情况下允许对应的入站端口就行了。下同。
测试
我们在实际使用前,先进行测试。
先在 ECS 上运行 frps:
1 | /root/frps/frps -c /root/frps/frps.ini |
再在树莓派上运行 frpc:
1 | /home/pi/frpc/frpc -c /home/frpc/frpc.ini |
为了方便讲解,上面的路径使用了绝对路径,使用对应的相对路径也是可以的。
观察输出,如果输出没有错误,那就用 SSH 连接一下
example.com
,记得把端口号改成
6022
。如果能够连上,就说明没有问题了。这时按
Ctrl
+ C
停掉两边的程序。
后台运行与自启动
我们实际运行中总不能运行这个命令,把这个窗口挂在电脑上吧,不然关掉了程序就停了。为此,我们还要想一个方法,让它后台运行。
让一个程序后台运行的方法比较多,我们这里使用比较方便的一个方法:将它做成服务。这样的好处是我们能够用一条命令实现它的启动、停止、重启、自启动和取消自启动。尤其是自启动,这也是是我们需要的。
创建服务的方式在两台机器上都差不多,我这里就以 ECS 上面的 frps 为例吧,在树莓派上操作的时候记得换成 frpc 及相关的内容。
首先我们在 /lib/systemd/system/
中创建一个文件
frps.service
(这里面 .service
之前的名字取一个能够记住的就行,但是要注意前后一致),内容如下,保存:
1 | [Unit] |
之后执行下面的命令开启服务:
1 | service frps start |
之后在树莓派上进行类似操作,但是还要修改 frpc.ini
,在
[common]
字段增加如下条目:
1 | # 由于树莓派没有时钟,开机后时间不对,frpc 访问服务器时会发生错误,所以此项必填 |
这个操作非常重要。我之前没有进行设置,结果第二天树莓派开机了,frp 却没有启动成功。当时我在宿舍,带着电脑去了办公室,查了日志才发现这个问题。
执行对应的 frpc 服务。测试一下,如果没有问题,继续以下操作。
在 ECS 上执行以下命令以实现自启动:
1 | systemctl enable frps.service |
在树莓派上进行类似操作。再重启一下树莓派进行测试,如果重启后能够通过外网连接树莓派,那么就成功了。
远程桌面
既然 SSH 能够连接上,我们再考虑一下连接其他的东西吧,比如那台十一年前的笔记本电脑。
远程桌面和 SSH 一样,都是使用 TCP
进行连接的,不过远程桌面的默认端口号是 3389
。
在进行下面的操作之前,我已经设置了网络共享,而且把电脑的远程桌面打开了。
在树莓派的 frpc.ini
中添加以下内容:
1 | [RDP] |
到 ECS 的控制台中允许 6389
端口入站方向的 TCP 连接。
重启 frpc
服务:
1 | service frpc restart |
然后使用远程桌面连接工具连接 example.com:6389
:
如果成功的话,就没什么问题了。
我之前以为要让笔记本电脑在树莓派之下的网络才行,当时还费很大力气开了树莓派的无线热点,之后发现只要笔记本电脑与树莓派在同一网络即可……
之后我成功地使用远程桌面连接在宿舍为室友远程打印了准考证。
我之前在树莓派上安装了
xrdp,可以使用远程桌面连接访问树莓派的图形环境。需要让它也能够远程连接,如法炮制即可,不过把
[RDP]
改一下,把对应的 IP 改成
127.0.0.1
,把对应的端口号改一下就行。不过 xrdp 的性能不如
Windows 原生的远程桌面好,但是总比 VNC 好多了吧。
分开服务
这里注意一下,如果你在外网使用 SSH 连接树莓派,在重启 frpc 服务的时候,SSH 的连接会中断。虽然能够重新连接,但是如果没法重新连接的话就非常尴尬了。我就遇到过这种情况:配置文件写错,导致 frp 重启失败,不得不跑到办公室解决问题。
经过我的测试,发现在端口号不冲突的情况下,同一台设备上能够运行多个
frpc。这样的话,我们可以尝试将 SSH 的部分另外写一个 ini 文件(注意
[common]
部分也要写上),将对应的命令写成
frpc_ssh.service
的服务,设置开启、自启动。这样一来,当我们在 SSH 上重启 frpc
的时候,就不会影响到 SSH 了。
运行树莓派上的网站
很多人用 ngrok 和 frp
的目的就是把本地的网站映射到公网地址上进行测试。我们假定在树莓派的
80
端口上运行着网站,希望将其映射到
pi.example.com
。
可以在 ECS 的 frps.ini
中的 [common]
字段中添加如下的配置:
1 | # 映射到虚拟主机的 HTTP 端口,不要有冲突 |
在树莓派的 frp.ini
中添加以下配置:
1 | # 取一个易懂的不重复的名字 |
到 ECS 的控制台中允许 80
、6080
端口入站方向的 TCP 连接。
在 example.com
的域名解析配置中,添加 A 记录
*
到 ECS 的 IP 地址。
在两边重启 frp 相关的服务。这时候访问
pi.example.com
,即可访问树莓派上的网站。
类似的方法还可以以特定域名访问、运行 HTTPS 协议的网站,详细的话可以看看官方的文档。
实际操作中非常不建议使用 *
这样的 A 记录,可以建立
*.test
这样的 A 记录,对应的部分也要做修改。
结尾
frp 的配置还有很多,可以看看官方文档。而且官方就有中文文档,相当方便。