在NAS上部署.NET版本的WOL远程开机服务

在本文中,我们将以部署基于.NET的WOL远程开机服务为例,详细介绍如何利用Docker技术在群辉部署ASP.NET服务。同时,我们还将展示如何对原有的控制台WOL进行改造,以及如何使用SignAuthorization简易URL验签类库。文章相关的代码开源地址:https://github.com/sangyuxiaowu/WakeOnLan?wt.mc_id=DT-MVP-5005195

文章目录

  • [1. 背景](#1. 背景)
  • [2. 准备工作](#2. 准备工作)
  • [2.1 创建 WebAPI 服务](#2.1 创建 WebAPI 服务)
  • [2.2 迁移原有代码](#2.2 迁移原有代码)
  • [2.3 加入 URL 验签](#2.3 加入 URL 验签)
  • [3. 在NAS部署](#3. 在NAS部署)
    • [3.1 Docker 镜像打包](#3.1 Docker 镜像打包)
    • [3.2 导出与导入](#3.2 导出与导入)
  • [4. 测试与使用](#4. 测试与使用)
    • [4.1 测试](#4.1 测试)
    • [4.2 部署](#4.2 部署)
    • [4.3 使用](#4.3 使用)
  • [5. 总结](#5. 总结)

1. 背景

在之前的文章《使用.NET实现WOL唤醒远程开机》中,我们已经成功实现了一个基于.NET的控制台程序,用于控制设备的远程唤醒功能。然而,为了实现远程控制访问,我们需要将这个控制台程序转换为WebAPI形式,并进行相应的部署。

通过本篇文章你会了解到:

  • APS.NET 项目的容器化
  • Docker 镜像的导出
  • 群辉 Docker 的使用
  • 远程网络唤醒服务的部署
  • SignAuthorization 简易URL验签类库的使用

2. 准备工作

在开始部署之前,请确保您已经拥有一台支持Docker的群辉NAS设备。当然,您也可以选择其他方式部署ASP.NET服务。

2.1 创建 WebAPI 服务

首先,我们需要创建一个WebAPI服务。在本教程中,我们将使用minAPI来实现轻量级的API,并启用Docker容器化支持。启用后,会在项目目录自动生成 `Dockerfile`` 文件。

2.2 迁移原有代码

接下来,我们需要将原有的控制台程序中的WOL唤醒功能代码迁移到新创建的WebAPI服务中。

这里我们单独写一个 WOL 的类来处理网络唤醒包数据的发送实现:

cs 复制代码
using System.Net.Sockets;
using System.Net;

namespace WakeOnLan
{
    internal class WOL
    {
        internal static void Send(string macAddress)
        {
            byte[] magicPacket = CreateMagicPacket(macAddress);
            SendMagicPacket(magicPacket);
        }

        static byte[] CreateMagicPacket(string macAddress)
        {
            byte[] macBytes = ParseMacAddress(macAddress);
            byte[] magicPacket = new byte[6 + (6 * 16)];

            for (int i = 0; i < 6; i++)
            {
                magicPacket[i] = 0xFF;
            }

            for (int i = 6; i < magicPacket.Length; i += 6)
            {
                Array.Copy(macBytes, 0, magicPacket, i, 6);
            }

            return magicPacket;
        }

        static byte[] ParseMacAddress(string macAddress)
        {
            string cleanedMacAddress = macAddress.Replace(":", "").Replace("-", "");

            if (cleanedMacAddress.Length != 12)
            {
                throw new ArgumentException("Invalid MAC address format");
            }

            byte[] macBytes = new byte[6];

            for (int i = 0; i < 6; i++)
            {
                macBytes[i] = Convert.ToByte(cleanedMacAddress.Substring(i * 2, 2), 16);
            }

            return macBytes;
        }

        static void SendMagicPacket(byte[] magicPacket)
        {
            using (UdpClient udpClient = new UdpClient())
            {
                udpClient.Connect(IPAddress.Broadcast, 9);
                udpClient.Send(magicPacket, magicPacket.Length);
            }
        }

    }
}

另外增加一个帮助类,用于 MAC 地址检查和设备是否在线的 Ping 测试:

cs 复制代码
internal class Helper
{
    internal static bool IsValidMacAddress(string macAddress)
    {
        Regex regex = new Regex("^([0-9a-fA-F]{2}[:-]?){5}([0-9a-fA-F]{2})$");
        return regex.IsMatch(macAddress);
    }

    internal static bool Ping(string iP)
    {
        // 检查IP是否在线
        Ping ping = new Ping();
        PingReply pingReply = ping.Send(iP,100);
        return pingReply.Status == IPStatus.Success;
    }
}

2.3 加入 URL 验签

为了确保WebAPI服务的访问安全,我们将加入简易且安全的SignAuthorization URL验签机制。

可以通过 Nuget 管理工具搜索或者执行直接命令安装:

dotnetcli 复制代码
Install-Package Sang.AspNetCore.SignAuthorization

安装完成后,需要在 Program.cs 进行简单的配置,从 appsettings.json 读取配置的 token 即可。

cs 复制代码
app.UseSignAuthorization(opt => {
    // 从配置文件读取 Token
    opt.sToken = app.Configuration["Token"];
});

引入 SignAuthorization 后进行简单的声明就可以让接口必须进行 URL 验签才可以访问,这里为了方便调试,只在生产环境起效,添加了 SignAuthorizeAttribute,比如下面的唤醒接口:

cs 复制代码
app.MapGet("/wol", (string mac) =>
{
    if (!Helper.IsValidMacAddress(mac))
    {
        return new CallBack(false, 400, "MAC地址格式错误");
    }
    WOL.Send(mac);
    return new CallBack(true, 200, "发送成功");
})
#if DEBUG
.WithOpenApi(operation => new(operation)
{
    Summary = "执行网络唤醒",
    Description = "通过传入MAC地址唤醒局域网内的设备"
})
#else
.WithMetadata(new SignAuthorizeAttribute())
#endif
;

最后添加一个从配置文件展示设备列表的接口,整体的迁移工作就可以完事了:

cs 复制代码
app.MapGet("/devices", () =>
{
    // 从配置文件读取设备列表
    var devices = app.Configuration.GetSection("Devices").Get<List<Device>>();
    // 判断IP是否在线
    Parallel.ForEach(devices, (device) =>
    {
        device.Online = Helper.Ping(device.IP);
    });
    return new CallBack<List<Device>>(true, 200, "获取成功", devices);
})
#if DEBUG
.WithOpenApi(operation => new(operation)
{
    Summary = "获取设备配置列表",
    Description = "获取配置的设备信息"
})
#else
.WithMetadata(new SignAuthorizeAttribute())
#endif
;

3. 在NAS部署

3.1 Docker 镜像打包

在部署前,我们需要先进行镜像制备,这里我们有两种主要方法可以选择。首先,可以在云端创建镜像,然后通过群辉的Docker管理后台通过 URL 方式添加。此外,另一种更常用的方法是在本地进行镜像制备。在这种情况下,我们同样有两种途径可供选择。

第一种方案是通过SSH登录群辉,直接执行Docker构建。为了实现这个目的,需要将项目文件拷贝到NAS上,然后在项目目录中执行相应的构建命令。这种方法的优点是可以直接在NAS上完成构建过程,从而节省了将镜像从本地上传到NAS的时间。

不过,这种方式需要在管理后台开启SSH,为了安全起见这个功能一般是不建议开启的。开开关关的折腾也挺不方便的。

一般的做法是在本地,如通过 wsl 打包 Docker 镜像(可以使用 Docker Desktop 或),然后导出镜像文件,最后通过群辉的管理后台上传镜像文件。

无论哪种方式制备镜像,我们只需要进入项目目录,执行打包命令:

bash 复制代码
docker build -t wol -f Dockerfile ..

注意: 这里的 Dockerfile 需要根据项目的情况修改默认的模板,可以查看今天推送的另一篇文章。

3.2 导出与导入

如果你没有使用 NAS 上的 Docker 进行打包,则需要导出,可以通过下面的指令:

bash 复制代码
docker save -o wol.tar wol

特别注意,这里会导出 wol:latest,不要通过查询 Image ID 的方式传参,这样导入的镜像会失去原有的 name 和 tag 。这种情况在群辉管理后台是无法显示这样的镜像的。

执行导出后,我们会得到一个 wol.tar 文件。在群辉管理后台上传即可。

4. 测试与使用

4.1 测试

如果使用 wsl 生成,我们直接启动镜像即可测试:

bash 复制代码
docker run -d -p 8080:8080 --name wol-1 wol

以上指令仅用于测试服务能否访问,无法实际使用

4.2 部署

在群辉的管理后台,我们也可以直接创建容器。需要特别注意的是,因为项目的特殊性,这里需要使用宿主机的本地网络,这样才可以发送唤醒包。

如果你有修改默认端口的需求,则需要通过修改环境变量 ASPNETCORE_HTTP_PORTS

对于设备列表的修改,则需要通过修改 appsettings.json 配置文件,这里除了在制备 Docker 镜像前修改外也可以通过进入容器内部或是在管理后台映射配置文件到 NAS 存储上。

4.3 使用

正式环境中 SignAuthorization 的配置是生效的,我们需要通过 URL 签名的方式访问服务的API。服务对外提供的是API调用,所以我们一般需要通过编程的方式来调用。签名方法可以查看 SignAuthorization 项目的介绍。同时,也可以关注后续项目增加的简易 Web 页面。

5. 总结

本文详细介绍了如何将基于.NET的WOL远程开机服务控制台程序迁移到minAPI创建的WebAPI服务中,并使用群辉的Docker技术进行部署。此外,我们还介绍了如何加入简易且安全的SignAuthorization URL验签机制,以确保远程访问的安全性。希望本文能为您提供实际操作的指导和帮助。

相关推荐
霍先生的虚拟宇宙网络16 分钟前
.net 支持跨平台(桌面)系列技术汇总
.net
djk888834 分钟前
.net的winfrom程序 窗体透明&打开窗体时出现在屏幕右上角
.net
九鼎科技-Leo10 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
dot.Net安全矩阵15 小时前
.NET 通过模块和驱动收集本地EDR的工具
windows·安全·web安全·.net·交互
zls36536515 小时前
.NET开源实时应用监控系统:WatchDog
.net
djk888815 小时前
.net将List<实体1>的数据转到List<实体2>
数据结构·list·.net
Crazy Struggle20 小时前
功能齐全的 WPF 自定义控件资源库(收藏版)
.net·wpf·ui控件库
时光追逐者1 天前
.NET 9 中 LINQ 新增功能实操
开发语言·开源·c#·.net·.netcore·linq·微软技术
zls3653651 天前
.NET高效下载word文件
开发语言·c#·word·.net
八荒我为王1 天前
c#编码技巧(十九):各种集合特点汇总
c#·.net