title: 使用 raspberry 配合 frp 来进行远程开机 tags:
一直有在外操作家里电脑的需求,远程控制这一步好解决,一般是通过 TeamViewer 来进行。但是前提之一是需要家中电脑时刻处于开机状态,但是由于电脑是台式即使待机也比平常笔记本的功率要高不少(可以看一下半个月的电费),而且如果 24 小时开机的话,散热器风扇一直处于运行状态,会使机箱的灰尘增多,这样的话清灰频率又要大大增加了。
<!-- more --> <!-- ![5.png](https://i.loli.net/2018/07/19/5b507b12be317.png) --> <!-- {% asset_img 电费.webp 电费 %} -->所以需要一种可以远程开机的办法。
之前的方法是使用即时通讯软件让家中的室友帮忙开机,但是也只限于家中有室友的情况,如果室友去上班了,那就没办法了。 也想过训练猫来帮助我开机,但是奈何这猫实在太蠢,朽木不可雕也。而且就算是训练成功了,那当我需要开机时,我该怎么通知到猫呢?这也是一个问题。 在试验过各种方法后,最后我使用了树莓派(raspberry)结合 frp 的方式来完成我的需求。
需要用到的设备有:
用来进行远程开机以及远程控制的设备一台;
具有 IP/MAC绑定 功能的路由器一台;
树莓派一台;
支持 WOL 的 PC 一台;
带有公网 IP 的服务器一台。
首先是家中局域网的配置,PC 和 树莓派要位于同一局域网,然后在路由器中把两者的 MAC 和 IP 进行绑定。这里需要注意的是 MAC 不是代表一台设备而是一个网卡,所以在设置树莓派的 MAC 地址的时候需要根据当前树莓派连接路由器的方式来设置。我使用的路由器可以直接查看设备的 MAC 地址。如下:
<!-- ![Routerlist.png](https://i.loli.net/2018/07/19/5b507b1a3f9aa.png) --> <!-- {% asset_img Routerlist.webp Routerlist %} -->如果路由器无法查看 MAC 地址或者设备太多无法区分,那么在 Windows 系统下可以使用
ipconfig -all
来查看
<!-- ![MACWindows.png](https://i.loli.net/2018/07/19/5b507b1a4128f.png) --> <!-- {% asset_img MACWindows.webp MACWindows %} -->在 raspberry 下可以使用
ifconfig
来查看
<!-- ![MACraspberry.png](https://i.loli.net/2018/07/19/5b507b1a4292a.png) --> <!-- {% asset_img MACraspberry.webp MACraspberry %} -->可以看到树莓派有两个 MAC 地址,由于我是使用无线连接所以我选择的是第二个 wlan0。 然后使用 IP/MAC绑定 功能将两台设备与 IP 进行绑定,绑定的时候建议就选择当前使用的 IP 以免用了其他设备正在使用的 IP,造成 IP 冲突。 如果绑定了其他的 IP,请在绑定成功后重启设备。
然后是要配置 PC 使其可以支持 WOL(wake-on-LAN)开机。WOL 是一种电源管理功能,中文译为 网络唤醒,以下是 Wiki 对其作出的解释:
Wake-on-LAN 简称 WOL 或 WoL,中文多译为「网络唤醒」、「远程唤醒」技术。WOL是一种技术,同时也是该技术的规范标准,它的功效在于让已经进入休眠状态或关机状态的电脑,透过局域网(多半为以太网)的另一端对其发令,使其从休眠状态唤醒、恢复成运作状态,或从关机状态转成引导状态。此外,与WOL相关的技术也包括远程下令关机、远程下令重启等相关的遥控机制。
它的具体方法就是向要启动的设备发送一个魔法数据包(Magic Packet):
魔法数据包(Magic Packet)是一个广播性的帧(frame),透过端口7或端口9进行发送,且可以用无连接(Connectionless protocol)的通信协议(如UDP、IPX)来传递,不过一般而言多是用UDP,原因是Novell公司的Netware网络操作系统的IPX协议已经愈来愈少机会被使用。 在魔法数据包内,每次都会先有连续6个"FF"(十六进制,换算成二进制即:11111111)的数据,即:FF FF FF FF FF FF,在连续6个"FF"后则开始带出MAC地址信息,有时还会带出4字节或6字节的密码,一旦经由网卡侦测、解读、研判(广播)魔法数据包的内容,内容中的MAC地址、密码若与电脑自身的地址、密码吻合,就会启动唤醒、引导的程序。
所以我们要先设置 BIOS 打开「网卡唤醒」这一功能,由于各个品牌主板的 BIOS 各不相同,所以设置的方法也各式各样,大家可以自行搜索「wake on lan 设置」,来寻找正确的方式。不过大多是在 电源管理(Power Management Setup)中。 然后是系统上的设置,这里我以 Windows 10 17134.165 版本为例。 首先右键「网络」-「属性」来打开「网络和共享中心」面板:
<!-- ![4.png](https://i.loli.net/2018/07/19/5b507b129fdee.png) --> <!-- {% asset_img 4.webp 网络和共享中心 %} -->在左侧单击「更改适配器设置」-右键你现在正在使用的网卡-「属性」来打开「属性」面板:
<!-- ![1.png](https://i.loli.net/2018/07/19/5b507b12983ac.png) --> <!-- {% asset_img 1.png 更改适配器设置 %} -->单击上方的「配置」-选择「高级」选项卡-在属性类别中将「关机 网络唤醒」和「魔术封包唤醒」的值设置为「开启」:
<!-- ![3.png](https://i.loli.net/2018/07/19/5b507b129f1e7.png) --> <!-- {% asset_img 3.webp 高级 %} -->选择「电源管理」选项卡-勾选「允许计算机关闭此设备以节约电源」和「允许此设备唤醒计算机」选项:
<!-- ![2.png](https://i.loli.net/2018/07/19/5b507b1298186.png) --> <!-- {% asset_img 2.webp 电源管理 %} -->就此,PC 端的设置已经完成了。
带公网 IP 的服务器,大家可以去阿里云或者腾讯云买一台最低配的就可以了,我的这台是之前在腾讯云薅羊毛薅的。 这个服务器的作用主要是运行 frp 的服务端来使局域网内的树莓派可以内网穿透。 frp 是一个免费的开源的内网穿透软件,而且部署简单方便。具体方式如下:
我们可以在 https://github.com/fatedier/frp/releases 下载指定架构下的版本,我在腾讯云服务器上使用的 Ubuntu 系统,所以选择的是 frp_0.20.0_linux_amd64.tar.gz
这个版本。可以下载下来使用 FTP 来放到服务器上,也可以在服务器上使用:
wget https://github.com/fatedier/frp/releases/download/v0.20.0/frp_0.20.0_linux_amd64.tar.gz
来直接下载到服务器上。
下载完成后使用:
tar -zxvf frp_0.20.0_linux_amd64.tar.gz
解压文件。
cd frp_2.20.0_linux_amd64
rm
命令来删除 frpc
和 frpc.ini
两个文件rm frpc frpc.ini
frps.ini
vim frps.ini
更改配置如下:
[common]
bind_port = 7000 #与客户端绑定的进行通信的端口
vhost_http_port = 6081 #访问客户端web服务自定义的端口号
注:
「#」 后面的是注释,可以不写;
这边 Vim 的用法可以上搜索引擎查一下,这里不多赘述。
./frps -c ./frps.ini
这个是前台启动服务,会输出日志信息,是用来调试的用的,到时调试成功了就可以使用后台服务启动:
nohup ./frps -c ./frps.ini &
至此,服务器也设置完成。
我现在使用的是 Raspberry 3B,当时是在淘宝 ¥195 的价格买的,如果配上电源以及 SD 卡的等配件一共是 ¥278.9。清单如下:
<!-- ![list.png](https://i.loli.net/2018/07/19/5b507b12b3fed.png) --> <!-- {% asset_img list.webp list %} -->之后的系统安装我就不在这详细说明了,网上有很多详细的教程。 树莓派的配置和服务器配置其实是差不多的,不同的是服务器上的部署的是 frp 的服务端,而树莓派上的部署的是客户端。 从下载到解压的步骤和服务器端是一模一样的,只要照着之前的步骤做就可以了。 从第三步删除文件开始有所不同:
在服务器上我们删除的是 frpc
和 frpc.ini
,这两个是 frp 的客户端程序和客户端配置文件,同理我们在树莓派也就是服务器端上就要删除 frps
和 frps.ini
这两个文件:
rm frps frps.ini
frpc.ini
vim frpc.ini
更改配置如下:
[common]
server_addr = 118.126.***.***
server_port = 7000
[ssh]
type = tcp
local_ip = 192.168.1.100
local_port = 22
remote_port = 6022
[mysql]
type = tcp
local_port = 3306
remote_port = 3306
server_addr
即为服务器的公网 IP 的地址,server_port
为之前在服务端配置时的 bind_port
,这里我用的是 7000
。 然后是需要内网穿透的服务的配置,我这里写了两个,一个是 SSH,一个是 MySQL。如果只要能进行远程连接的话我们只需要 SSH 的配置就好了,这里要注意的就是 remote_port
,自定义的端口号,不要填 22
,因为在服务器上已经被占用了(被用于服务器的 SSH),所以你要选一个没被占用的端口来使用,这里我用的是 6022
。
./frpc -c ./frpc.ini
同样的,后台服务启动是:
nohup ./frpc -c ./frpc.ini &
现在我们可以在自己的 PC 上使用以下命令来访问树莓派了:
ssh -p 6022 118.126.***.***
然后键入树莓派的密码就可以了:
<!-- ![SSHraspberryPC.png](https://i.loli.net/2018/07/19/5b507b1a44208.png) --> <!-- {% asset_img SSHraspberryPC.png SSHraspberryPC %} -->当然也可以用手机的移动网络来访问:
<!-- ![SSHPhone.png](https://i.loli.net/2018/07/19/5b507b1a5450c.png) --> <!-- {% asset_img SSHPhone.webp SSHPhone %} -->至此我们已经成功的内网内网穿透了,即可以从外网访问内网设备了,接下来我们就要通过树莓派来使家中的 PC 开机了。
这里我找了好多软件,测试了好久,不是没有 Linux 平台的,就是不能用。所以最后还是用 Python 了,具体代码如下:
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
import argparse
import socket
import struct
BROADCAST_IP = '255.255.255.255'
DEFAULT_PORT = 9
def create_magic_packet(macaddress):
if len(macaddress) == 12:
pass
elif len(macaddress) == 17:
sep = macaddress[2]
macaddress = macaddress.replace(sep, '')
else:
raise ValueError('Incorrect MAC address format')
# Pad the synchronization stream
data = b'FFFFFFFFFFFF' + (macaddress * 16).encode()
send_data = b''
# Split up the hex values in pack
for i in range(0, len(data), 2):
send_data += struct.pack(b'B', int(data[i: i + 2], 16))
return send_data
def send_magic_packet(*macs, **kwargs):
packets = []
ip = kwargs.pop('ip_address', BROADCAST_IP)
port = kwargs.pop('port', DEFAULT_PORT)
for k in kwargs:
raise TypeError('send_magic_packet() got an unexpected keyword '
'argument {!r}'.format(k))
for mac in macs:
packet = create_magic_packet(mac)
packets.append(packet)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.connect((ip, port))
for packet in packets:
sock.send(packet)
sock.close()
def main(argv=None):
parser = argparse.ArgumentParser(
description='Wake one or more computers using the wake on lan'
' protocol.')
parser.add_argument(
'macs',
metavar='mac address',
nargs='+',
help='The mac addresses or of the computers you are trying to wake.')
parser.add_argument(
'-i',
metavar='ip',
default=BROADCAST_IP,
help='The ip address of the host to send the magic packet to.'
' (default {})'.format(BROADCAST_IP))
parser.add_argument(
'-p',
metavar='port',
type=int,
default=DEFAULT_PORT,
help='The port of the host to send the magic packet to (default 9)')
args = parser.parse_args(argv)
send_magic_packet(*args.macs, ip_address=args.i, port=args.p)
if __name__ == '__main__': # pragma: nocover
main()
我们把上面的代码保存为 *.py
格式,例如 wol.py
然后通过 ftp 传输到树莓派上去。 然后在存有这个 wol.py
的文件夹下使用:
python wol.py E0:D5:5E:88:88:88
E0:D5:5E:88:88:88
就是你需要启动的 PC 的 MAC 地址了。 回车后发现没有任何提示,这是正常了,因为在 Linux 中,没有消息就是好消息。 如果你只需要启动一台 PC,而且你不想记录这么长的 MAC 地址(通常也不需要你记录,因为你可以在终端通过上下键来显示历史使用过的命令),你可以将你的 MAC 地址写入到代码中去,这样就可以一劳永逸了。 至此,你已经可以通过树莓派来启动你的 PC 了,快关闭你的电脑试一试吧。
事后,我用 Wireshark 抓了包,找到了这个 Magic Packet:
<!-- ![6.png](https://i.loli.net/2018/07/19/5b507b12b69cb.png) --> <!-- {% asset_img 6.webp MagicPacket %} -->发现和 Wiki 上说的一样:以 6
个 FF
开始,并且重复 16
遍 MAC 地址。
可以看到,我在树莓派上的 frp 配置文件中有一个 MySQL 的条目:
[mysql]
type = tcp
local_port = 3306
remote_port = 3306
当如此设置后,并且在树莓派上安装 MySQL,就可以在外网用类似的方法来访问内网的数据库了。 同样的,我们知道,网站(HTTP)是通过 80
端口来传输的,由此如果我们在树莓派上有部署网站的话,那么就可以通过 frp 进行类似的配置(这部分可能会有一些不同),我们就可以在外网访问该网站了。
没有总结。