有时候我们经常需要用到家里或者公司的台式机,台式机不可能24小时开着,有点浪费资源,于是某些情况下需要远程开机。

远程开机需要主板支持网络唤醒功能,一般的台式机、笔记本、打印机、甚至NAS都有这个功能,但需要使用网线连接,无线貌似不支持

一般我们在路由器上安装远程唤醒命令行工具,命令行执行命令指定对应的机器MAC地址就能实现开机

现远程开机主流方案如下

  1. 购买设备,如向日葵开机棒等,再配置设备参数以便远程开机
  2. 路由器有公网IP,通过终端登录到路由器,在路由器上运行远程唤醒命令,唤醒直连的电脑主机
  3. 路由器没有公网IP,需要申请动态域名,比如在路由器后台配置花生壳动态域名,以便能登陆到路由器,对目标电脑执行命令远程唤醒

核心思想

  1. 电脑主机等支持远程唤醒,并开启该功能
  2. 在路由器上可以执行远程唤醒命令
  3. 如何连接到没有外网IP的路由器,可以通过vpn,内网穿透等功能

我的实现

目前需要手动执行命令开机那肯定不是我们想要的,不够便捷,于是如果能够让路由器循环执行某段脚本请求一个接口,通过该接口返回值来让路由器自动执行远程唤醒命令

那接口的逻辑怎么判断出是否要重启呢,可以通过我们网盘,或者服务上的某个文件变动、时间戳被更新,再或者将该接口暴露在外网,通过浏览器访问该接口,通知路由器发送唤醒命令

我的实现是我有一台云服务器,自建了Nextcloud网盘,手机端IOS也在用这个网盘,于是手机端编辑网盘里面某个固定文件的文件名,这个修改被网盘同步到服务器的文件系统,服务器上的Flask WEB在收到路由器的接口请求之后,检测文件系统中该文件名是否发生了变化,和老文件名做对比,有变化则返回给路由器对应开机的字符串,而后路由器会远程唤醒目标主机

实现的配置

1. 电脑主机配置

  • 电脑主机先要使用网卡连接到路由器
  • 确认主板支持网络唤醒Wake On Lan并开启,可以查看Bios电源选项,有的写的是PICI-E唤醒,也需要开启这一项
  • 主机系统设置允许远程唤醒

    • Windows打开 控制面板网络和 Internet网络连接 找到对应的有线网卡,点击属性-配置-电源管理,勾选允许被唤醒

    • Linux设置

      1. 先在系统网络设置或者电源管理中找到网络唤醒相关的设置,我这里是elementary OS,设置如下

    1. 安装网卡工具命令,查看网卡是否支持和开启

      $ sudo apt install -y ethtool 
      $ sudo ethtool  enp2s0   # 注意使用sudo权限,不然这两行可能不会显示
      ...
       Supports Wake-on: pumbg
              Wake-on: d
      ...
      
      kxw@kxw-PC:~/Desktop/$ cat /etc/rc.local 
      #!/bin/bash
      
      start() {
      /sbin/ethtool  -s enp2s0 wol g
      }
      
      start
      
      在Centos下这就足够了,开机便会执行这个文件
   注意 Wake-on 为d表示现在是disable状态,需要开启,使用如下命令开启

   `$ sudo /sbin/ethtool  -s enp2s0 wol g`

   这里如果只在命令行执行的话,下次重启该改动会失效,我们将其写入 /etc/rc.local文件,并给/etc/rc.local加入执行权限x
$ cat /etc/rc.local 
#!/bin/bash

start() {
/sbin/ethtool  -s enp2s0 wol g
}

start
   在Ubuntu下,/etc/rc.local这个文件可能没有,需要我们关注rc.local的systemd服务,修改对应的服务,添加启动脚本
$ cat /etc/systemd/system/rc-local.service 
[Unit]
Description=/etc/rc.local Compatibility
Documentation=man:systemd-rc-local-generator(8)
ConditionFileIsExecutable=/etc/rc.local
After=network.target

[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
RemainAfterExit=yes
GuessMainPID=no

[Install]
WantedBy=graphical.target
Alias=rc-local.service
   这里注意 ExecStart=/etc/rc.local start 这一行修改对就行

   最终需要看到 Wake-on: g 就ok了
$ sudo ethtool  enp2s0
...
    Supports Wake-on: pumbg
    Wake-on: g
...

2. 路由器配置

路由器需要能ssh或者telnet登陆进去,可以先看看路由器后台能否开启ssh或telnet登陆,一般刷了OpenWrt的路由器是可以的,其他品牌有的也可以

  1. 以我手上的OpenWrt为例:

    # opkg update
    # opkg install etherwake
  2. 需要查看路由器,Lan(也就是接电脑那一侧)网口的名字,我们在路由上查看

    root@OpenWrt:~# ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
    valid_lft forever preferred_lft forever
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP qlen 1000
    link/ether 04:xxx brd xxx
    inet6 fe80::6xxx scope link 
    valid_lft forever preferred_lft forever
    5: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 04:xxx8 brd xxx
    inet 192.168.2.1/24 brd 192.168.2.255 scope global br-lan
    valid_lft forever preferred_lft forever
    inet6 xxx scope global 
    valid_lft forever preferred_lft forever
    inet6 fe80::xxx scope link 
    valid_lft forever preferred_lft forever
    6: eth0.2@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-lan state UP qlen 1000
    link/ether 04:xxx brd xxx
    7: eth0.1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 04:xxx brd xxx
    inet6 fe80::6xxx scope link 
    valid_lft forever preferred_lft forever
    ...

这里看到就是br-lan这个网口

  1. 确定需要唤醒的主机的MAC地址

    • Linux直接终端运行ip a查看
    • windows用户去网络连接属性查看
  2. 准备路由器脚本

这里我们一般把脚本放在/etc/init.d/下,若不是OpenWtr系统,可能路径有些区别

   root@OpenWrt:~# cat /etc/init.d/getIsWake 
   #!/bin/sh /etc/rc.common
   # Copyright (C) 2008 OpenWrt.org
    
   START=97
   # 执行的顺序,按照字符串顺序排序并不是数字排序
    
   
   script_pid=$$
   
   echo $script_pid > /tmp/wake_script_pid.pid
   
   getExec() {
       while true; do
           result=`wget -q -O - http://ttt.cn:7653/kwen/route?token=sadsadsa*s-Q312`
           if [ "$result" == "startWake" ];then
               etherwake -i br-lan 10:7b:44:f2:67:9I
           fi
           sleep 5
       done
   }
   
   start(){
           getExec
   }
   stop(){
           kill `cat /tmp/wake_script_pid.pid`
   }
   restart(){
           kill `cat /tmp/wake_script_pid.pid`
           getExec
   }

这其中的stop restart函数都没有使用到,我们只需要关心如下代码

   getExec() {
       while true; do
           result=`wget -q -O - http://ttt.cn:7653/kwen/route?token=sadsadsa*s-Q312`
           if [ "$result" == "startWake" ];then
               etherwake -i br-lan 10:7b:44:f2:67:9I
           fi
           sleep 5
       done
   }
wget -q -O - http://ttt.cn:7653/kwen/route?token=sadsadsa*s-Q312这句代码向我的FLask服务器请求数据,
请求到的结果若是startWake字符串则开始运行远程唤醒命令etherwake -i br-lan 10:7b:44:f2:67:9I 
-i 为指定上一步查看到的lan网卡名, 
'10:7b:44:f2:67:9I' 为我电脑的MAC地址

服务器Flask代码配置

[root@tencent-host ~]# cat /data/route/route.py 
#!coding=utf-8
from flask import Flask, abort, Response, request
import os

import logging
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
handler = logging.FileHandler("/var/log/route.log")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)


app = Flask(__name__)
app.config["DEBUG"] = True

URI = '/kwen/route'
QUERY = 'token'

computer_status = "shutdown"

# 增加远程唤醒脚本判断
def wake():
    current_name = "/usr/bin/basename `ls /data/nextcloud/data/kkwen/files/B2-程序/wake*`"
    old_name = "cat /wake/wake.txt"
    try:
        new_flag = os.popen(current_name).read()
        old_flag = os.popen(old_name).read()
        if new_flag and new_flag != old_flag:
            os.popen("echo $(/usr/bin/basename `ls /data/nextcloud/data/kkwen/files/B2-程序/wake*`) > /wake/wake.txt")
            return True
    except Exception as e:
        logger.error(str(e))
        return False




@app.route(URI, methods=['GET'])
def get_route_ip():
    rsp = ""
    try:
        token = request.args.get(QUERY, '')
        if token != 'sadsadsa*s-Q312':
            return Response('')
        else:
            if wake():
                rsp = "startWake"
                logger.info("远程唤醒已开始执行")
        return Response(rsp)
    except Exception as e:
        print(e)
        abort(404)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=7653)

我会在 /data/nextcloud/data/kkwen/files/B2-程序/ 这个网盘目录下建一个wake.confXXX的文件,执行远程开机后将这个文件名记录在/wake/wake.txt中,每次收到路由器的请求之后,去查看/data/nextcloud/data/kkwen/files/B2-程序/这个目录下的以wake.conf开头的文件名,和/wake/wake.txt中的文件名做对比,如果不一样,就给路由器响应startWake字符串,让路由器唤醒主机

再上一张手机Nexcloud的截图,推荐大家使用这个网盘

开机之后的远程工具

  • 我使用的是VNC+自建的OpenVPN
  • 也可以使用向日葵电脑端和手机端

小贴士

经过一段时间的使用,我发现使用VNC远程Windows的时候,有一些弹窗会卡住,VNC操作不了,这时使用mstsc还可以操作

在Windows系统更新之后,貌似远程唤醒会有一些问题,有时候启动不了

最后修改:2021 年 01 月 26 日 02 : 36 PM