0%

使用 FRP 和 WakeOnLan 远程电脑的方法

在某些场景下,我们需要在外远程访问家中的电脑。例如,最近过年回家时,有些服务需要远程查看,因此我折腾了使用 FRP 远程访问家中 Mac 的方法,还有远程唤醒电脑的 WakeOnLan 方案。

使用 FRP 和 WakeOnLan 远程电脑的方法

本文的大纲如下:

  • 如何使用 FRP 远程
  • FRP 远程的体验
  • FRP 的安全性和 TLS 抓包
  • WakeOnLan 的需求
  • WakeOnLan 的配置
  • 最后

如何使用 frp 远程

FRP 的远程访问逻辑非常简单。由于家庭宽带通常不提供公网 IP(目前申请公网 IP 通常需要额外付费,具体方式需咨询运营商),因此需要通过服务器进行网络中转。

配置的过程中使用的是安全地暴露内网服务方式,这里简称为 stcp,使用的版本是v0.61.0

Mac 自带的远程访问方式为 VNC,需要打开「设置」,「共享」,「屏幕共享」,并且打开「允许使用密码控制屏幕」。

服务端 frps 的配置为 frps.toml,启动命令为 ./frps -c frps.toml

1
2
bindPort = 7100    # 服务器监听端口
auth.token = "xxx" # 服务器验证密码

在深圳的机器上,运行 FRP 客户端配置文件 frpc.toml 如下,启动命令为 ./frpc -c frpc.toml

1
2
3
4
5
6
7
8
9
10
11
serverAddr = "xxx" # 服务器域名
serverPort = 7100 # 服务器监听端口
auth.token = "xxx" # 服务器验证密码

[[proxies]]
name = "secret_ssh" # 名称要和访问者的配置保持一致
type = "stcp"
# 只有与此处设置的 secretKey 一致的用户才能访问此服务
secretKey = "xxx"
localIP = "127.0.0.1"
localPort = 5900 # macOS 系统屏幕共享服务监听的端口号

在外电脑运行 frpc 配置为 frpc.toml,启动命令为 ./frpc -c frpc.toml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
serverAddr = "xxx" # 服务器域名
serverPort = 7100 # 服务器监听端口
auth.token = "xxx" # 服务器验证密码

[[visitors]]
name = "secret_ssh_visitor"
type = "stcp"
# 要访问的 stcp 代理的名字
serverName = "secret_ssh"
# 只有与此处设置的 secretKey 一致的用户才能访问此服务
secretKey = "xxx"
# 绑定本地端口以访问服务
bindAddr = "127.0.0.1"
bindPort = 6000

启动之后,打开 macos 自带的「屏幕共享」软件,按照配置连接127.0.0.1:6000,输入账号密码即可远程使用。

FRP 远程的体验

macOS 的远程使用的协议是 VNC 协议,相比于 Windows 的 RDP 协议体验会差一些。由于 macOS 的复杂动效和高分辨率,会很卡,把 macOS 的分辨率调整为 1080P,开启系统设置中的「减弱动态效果」,但是微信打开图片依然有渐变的动画,其他更深层次的优化设置没去研究了。

找了一下相关的帖子,例如 Mac 上最流畅不卡的远程控制另外一台 Mac 的方法是什么?求远程 mac 的最佳方式。在原生的 VNC 协议上,想要获得较好的体验就得加带宽,4Mbps 的带宽都很难获得较好的体验,最近云厂商出了峰值 200Mbps 的服务器体验会稍微好一点。其他类似 teamviewer 和向日葵之类的软件就没有去尝试了。

在「屏幕共享」连接成功后,点击顶部状态栏的「编辑」菜单,选择「使用共享的剪切板」,这样可以方便地在两台机器之间复制粘贴内容。文件传输方面,把文件拖动到目标电脑的「访达」目录即可。

FRP 的安全性和 TLS 抓包

另外对于 FRP 的安全性进行了简单的探究。

  1. 部署在公网服务器上的 FRP 服务如何不被别人盗用?
    在服务器的配置文件中设置了 auth.token = "xxx" # 服务器验证密码 来保证不知道 auth.token 的用户无法使用。
  2. FRP 协议传输数据的过程中是否有加密处理?
    在以前讨论里有流量被嗅探 #3193相关的讨论。在 2023 年 6 月,FRP v0.50.0 默认使用了 tls 协议来进行加密,但是在 frps 随机生成的证书没有校验,做到这个程度已经差不多了。如果要进一步提升安全性,就自己配置证书。
    我通过抓包也看到在三次握手完成之后,就开始走 TLS 协议。

WakeOnLan 的需求

原本到这里应该就结束了,让电脑永不休眠就可以了。然而我给电脑用上了「小米智能插座 3」,发现电脑在正常空跑的情况,在留存 Chrome、微信和 QQ 的情况下,功耗一般在 55-70w 之间。

如果是休眠状态,电脑功耗仅需要 3W。值得一提的是,我买了 Macmini M4,即使空跑也只有 3W 的功耗,苹果是真的省电。
按照 60w 的功率计算,一天大概需要 1.44 度电,按照 7 毛一度电,一天的电费需要 1 元,一年就是 365 元。

1
2
60*24/1000=1.44度
1.44*0.7=1元

啥都不干需要消耗这么多电力,这显然不太合理。虽说可以设置电脑连接电源时自动启动,通过智能插座来远程控制开关电源,但是这样做不满足我的需求。于是我使用 WakeOnLan(网络唤醒) 技术来唤醒休眠中的电脑。

WakeOnLan 的配置

WakeOnLan 的原理很简单,就是网卡监听收到的包,如果是特殊内容的魔术包就唤醒操作系统。目前绝大多数电脑都支持通过 WakeOnLan 来唤醒。 以我的 PC 为例,在 BIOS 中设置 PICE-E 和 Intel CNVi 为 Enable 状态即可。


设置好之后就需要从另外一个设备来唤醒,我尝试了使用群晖和路由器都可以办到,由于路由器一直跑并且不休眠的,所以最终选择使用路由器。我问了 AI 来生成一个唤醒的程序,给代码稍作改动就达到目的,我将代码和编译出来的执行程序都放到了 github 上的 wakeonlan_go

我的路由器是红米 AX6000,在路由器中执行命令可以看到基础系统是 openwrt,询问 AI 得知应该使用 linux 的 arm64 进行编译。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# cat /etc/os-release
NAME="OpenWrt"
VERSION="18.06-SNAPSHOT"
ID="openwrt"
ID_LIKE="lede openwrt"
PRETTY_NAME="OpenWrt 18.06-SNAPSHOT"
VERSION_ID="18.06-snapshot"
HOME_URL="http://openwrt.org/"
BUG_URL="http://bugs.openwrt.org/"
SUPPORT_URL="http://forum.lede-project.org/"
BUILD_ID="unknown"
LEDE_BOARD="mediatek/mt7986"
LEDE_ARCH="aarch64_cortex-a53"
LEDE_TAINTS="no-all busybox"
LEDE_DEVICE_MANUFACTURER="OpenWrt"
LEDE_DEVICE_MANUFACTURER_URL="http://openwrt.org/"
LEDE_DEVICE_PRODUCT="Generic"
LEDE_DEVICE_REVISION="v0"
LEDE_RELEASE="OpenWrt 18.06-SNAPSHOT unknown"

首先将文件拷贝到路由器的 /tmp 目录,然后将其移动到 /data 目录下。在命令行中执行以下命令即可唤醒电脑。

1
2
3
# 这里的 ip 我填的是,192.168.31.255,需要填写电脑所在的局域网的广播地址,家用路由器的 ip 一般是 192.168.1.x 这里广播地址应该填写 192.168.1.255
# 如果子网掩码不是 255.255.255.0,就涉及计算机网络知识,需要替换成对应的广播地址。
/data/wake_on_lan -mac="xxx" -ip="xxx"

到这里局域网的唤醒就已经成功了。还需要在外网也能访问路由器的命令行来执行命令,将路由器的 ssh 也是用 frp 的 stcp 模式进行内网穿透。这里要注意的是如何让路由器用守护进程的方式运行 frp,我找 AI 也问了脚本,创建文件 frp-service,给执行权限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/sh /etc/rc.common

# 给红米 AX6000 路由器使用的,所以命名为 frp-service
# 用于启动和停止 FRP Client
START=99 # 启动顺序,较高的数字表示较晚启动
STOP=10 # 停止顺序

# 描述信息
DESCRIPTION="FRP Client"

# 启动命令
start() {
echo "Starting FRP Client..."
/data/frp_0.61.0_linux_arm64/frpc -c /data/frp_0.61.0_linux_arm64/frpc.toml &
}

# 停止命令
stop() {
echo "Stopping FRP Client..."
killall frpc
}

# 重启命令
restart() {
echo "Stopping FRP Client..."
killall frpc
echo "Starting FRP Client..."
/data/frp_0.61.0_linux_arm64/frpc -c /data/frp_0.61.0_linux_arm64/frpc.toml &
}

就可以通过 /data/frp-service start 命令来启动服务在后台运行了。需要注意的是除了 /data 目录下的文件,其他文件都会在路由器重启时被重置。这里还有个稍微不爽的点是在唤醒后需要等 30 秒左右远程桌面才能重新连上。

最后

本文的需求只是暴露 TCP 服务,直接暴露 TCP 到公网容易被各种暴力破解扫描,所以使用了 FRP 提供的 STCP 方式。如果只需要暴露 http 服务,那么再走 nginx 类的方向代理程序使用 https 对外提供服务比较安全,具体可以看很多年前写过的使用 Frp 内网穿透进行开发

由于我只用了 macOS 的远程访问,FRP 在 windows 上设置开机启动和守护进程的方式不太一样,有朋友尝试后也完成了设置,可以看看Windows 设置 frpc 开机自动启动(不管用户是否登陆都要运行)

由于现在已经满足了我的需求,比较流行的异地组网,如 headscale 或者 tailscale 的方案没有继续深入研究了。

听说好看的人都关注了我的公众号《泫言》