【實戰】ASP.NET Core 6 部署在 ARM 樹莓派實現 DDNS 和網絡喚醒


家里有個樹莓派3B(Raspberry Pi 3B Arm 架構 32 位),放在家里一直在吃灰,由於 .NET Core 程序能跨平台,所以准備寫個網站部署到樹莓派上面。家里寬帶有公網 IP 地址,但是每次重啟路由器后 IP 地址都會發生變化,華碩路由器的免費 DDNS 並不太好用(家里 IP 變了,域名解析並沒有及時生效)。家里有台 DELL 台式機和 DELL EMC 服務器,所以,准備使用 ASP.NET Core 寫一個 DDNS 服務和在線網絡喚醒工具。

有了 DDNS 可以及時的獲取到家里的外網 IP 地址,使用網絡喚醒功能可以喚醒我的 DELL 台式機電腦,方便查閱家中資料。

使用 ASP.NET Core 6 寫的網站部署在樹莓派已經穩定運行 3 個多月了,沒有任何問題。



安裝 AspNetCore 運行時

首先,樹莓派需要安裝 Raspberry Pi OS 系統,教程如下:

樹莓派3B(Raspberry Pi 3B)安裝 Raspberry Pi OS 系統
https://www.itsvse.com/thread-10052-1-1.html


然后在樹莓派上面安裝 AspNetCore Runtimes,使用 SSH 登錄到樹莓派主機中,使用 sudo -i 切換到 root 權限下,創建 /usr/dotnet 文件夾,命令如下:

mkdir -p /usr/dotnet && cd /usr/dotnet

下載 aspnetcore-runtime-6.0.1-linux-arm.tar.gz 並解壓,命令如下:

wget https://download.visualstudio.microsoft.com/download/pr/ff3b2714-0dee-4cf9-94ee-cb9f5ded285f/d6bfe8668428f9eb28acdf6b6f5a81bc/aspnetcore-runtime-6.0.1-linux-arm.tar.gz
tar -zxvf aspnetcore-runtime-6.0.1-linux-arm.tar.gz

創建軟鏈接,命令如下:

ln -s /usr/dotnet/dotnet /usr/bin/dotnet

至此,ASP.NET Core 網站所需要的運行環境安裝完畢,查看安裝的運行時,如下圖:



DDNS 動態域名服務

調用 DNSPod 的接口來實現 DDNS 動態域名服務,接口文檔:https://docs.dnspod.cn/api/modify-records/

使用 VS 2022 新建一個 ASP.NET Core 6 的 MVC 項目,新建 DNSPodOptions.cs 文件配置調用接口所需的參數,如下:

namespace HomeCloud.Models
{
    public class DNSPodOptions
    {
        public const string Name = "DNSPod";

        public string Url { get;set; }

        public string LoginToken { get;set; }

        public string Format { get; set; }

        public string Domain { get; set; }

        public string RecordId { get; set; }

        public string RecordType { get; set; }

        public string RecordLineId { get; set; }

        public string SubDomain { get; set; }

    }
}

appsettings.json 添加如下配置:

"DNSPod": {
    "Url": "https://dnsapi.cn/Record.Modify",
    "LoginToken": "xxxx",
    "Format": "json",
    "Domain": "itsvse.com",
    "RecordId": "xxxx",
    "RecordType": "A",
    "RecordLineId": "0",
    "SubDomain": "xxxx"
  }

修改 Program.cs 文件,將配置信息映射到 DNSPodOptions 類,代碼如下:

builder.Services.Configure<HomeCloud.Models.DNSPodOptions>(
    builder.Configuration.GetSection(HomeCloud.Models.DNSPodOptions.Name));

新建 DDNSWorker.cs 文件,創建后台服務,一分鍾獲取一次 IP 地址,如果 IP 地址有發生變化,則調用 DNSPod 的接口來更新域名解析。(注意:如果1小時之內,提交了超過5次沒有任何變動的記錄修改請求,該記錄會被系統鎖定1小時,不允許再次修改。比如原記錄值已經是 1.1.1.1,新的請求還要求修改為 1.1.1.1。)

代碼如下:

using HomeCloud.Models;
using Microsoft.Extensions.Options;
using System.Net;
using System.Text;

namespace HomeCloud.Workers
{
    public class DDNSWorker : BackgroundService
    {

        private readonly ILogger<DDNSWorker> _logger;
        private readonly IOptions<DNSPodOptions> _options;
        public static string clientIP = string.Empty;

        public DDNSWorker(ILogger<DDNSWorker> logger, 
            IOptions<DNSPodOptions> options)
        {
            _logger = logger;
            _options = options;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            
            await Task.Run(async () =>
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    try
                    {
                        var temp = GetClientIP();
                        if (!string.IsNullOrWhiteSpace(temp))
                        {
                            if (!temp.Equals(clientIP))
                            {
                                clientIP = temp;
                                var ddnsRet = UpdateDDNS(_options.Value);
                                _logger.LogInformation($"更新 ddns 結果:{ddnsRet}");
                            }
                        }
                        _logger.LogInformation($"當前 ip 地址:{clientIP}");
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError("獲取 ip 異常", ex);
                    }
                    await Task.Delay(60 * 1000, stoppingToken);
                }
            }, stoppingToken);
        }

        /// <summary>
        /// GET請求與獲取結果
        /// </summary>
        public static string GetClientIP()
        {
            此處獲取到外網 ip 地址返回,為了防止別人調用我的接口,此處代碼略!
        }

        /// <summary>
        /// UpdateDDNS
        /// 如果1小時之內,提交了超過5次沒有任何變動的記錄修改請求,該記錄會被系統鎖定1小時,不允許再次修改。比如原記錄值已經是 1.1.1.1,新的請求還要求修改為 1.1.1.1。
        /// </summary>
        /// <returns></returns>
        public static string UpdateDDNS(DNSPodOptions options)
        {
            using var client = new HttpClient();
            HttpContent content = new StringContent($"login_token={options.LoginToken}&format={options.Format}&sub_domain={options.SubDomain}&domain={options.Domain}&record_id={options.RecordId}&value={clientIP}&record_type={options.RecordType}&record_line_id={options.RecordLineId}");
            content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
            var res = client.PostAsync(options.Url, content).Result;
            return res.Content.ReadAsStringAsync().Result;
        }
    }
}

修改 Program.cs 文件,注冊后台服務,代碼如下:

builder.Host.ConfigureServices(services => {
    services.AddHostedService<DDNSWorker>();
});

完整的 Program.cs 代碼,如下:

using HomeCloud.Workers;

var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureServices(services => {
    services.AddHostedService<DDNSWorker>();
});

// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.Configure<HomeCloud.Models.DNSPodOptions>(
    builder.Configuration.GetSection(HomeCloud.Models.DNSPodOptions.Name));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();


調試程序,可以正常調用 DNSPod 的接口,如下:


網絡喚醒(Wake On LAN)

Wake-on-LAN簡稱WOL或WoL,中文多譯為“網上喚醒”、“遠程喚醒”技術。WOL是一種技術,同時也是該技術的規范標准,它的功效在於讓已經進入休眠狀態或關機狀態的計算機,透過局域網(多半為以太網)的另一端對其發令,使其從休眠狀態喚醒、恢復成運作狀態,或從關機狀態轉成引導狀態。此外,與WOL相關的技術也包括遠程下令關機、遠程下令重啟等相關的遙控機制。

修改 HomeController 控制器,添加網絡喚醒的接口,代碼如下:

using HomeCloud.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Diagnostics;
using System.Net.Sockets;

namespace HomeCloud.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        
        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public IActionResult WOL(string mac)
        {
            WakeUpCore(FormatMac(mac));
            return Json(new { ret = true });
        }
      
        private static void WakeUpCore(byte[] mac)
        {
            //發送方法是通過UDP
            using UdpClient client = new UdpClient();
            //Broadcast內容為:255,255,255,255.廣播形式,所以不需要IP
            client.Connect(System.Net.IPAddress.Broadcast, 50000);
            //下方為發送內容的編制,6遍“FF”+17遍mac的byte類型字節。
            byte[] packet = new byte[17 * 6];
            for (int i = 0; i < 6; i++)
                packet[i] = 0xFF;
            for (int i = 1; i <= 16; i++)
                for (int j = 0; j < 6; j++)
                    packet[i * 6 + j] = mac[j];
            //喚醒動作
            int result = client.Send(packet, packet.Length);
        }

        private static byte[] FormatMac(string macInput)
        {
            byte[] mac = new byte[6];
            string str = macInput;
            //消除MAC地址中的“-”符號
            string[] sArray = str.Split('-');
            //mac地址從string轉換成byte
            for (var i = 0; i < 6; i++)
            {
                var byteValue = Convert.ToByte(sArray[i], 16);
                mac[i] = byteValue;
            }
            return mac;
        }
    }
}

編輯 Index.cshtml 頁面,添加 MAC 地址輸入框和按鈕,使用 Ajax 調用接口,代碼如下:

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Welcome itsvse.com</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
<div class="row">
    <div class="col-12">
       <input class="form-control" placeholder="mac 地址" id="mac" />
    </div>
    <div class="col-12 mt-2">
        <button class="btn btn-block btn-primary" onclick="powerOn();" >喚醒</button>
    </div>
</div>
@section Scripts{
    <script>
        function powerOn()
        {
            var mac =$("#mac").val();
            $.post("/Home/WOL",{mac:mac},function(ret){
                alert("ok");
            });
        }
    </script>
}

啟動項目,如下圖:



部署在樹莓派

使用 VS 2022 發布項目,將發布包上傳到樹莓派的 /home/pi/wol 文件夾下面,如下圖:




在 /etc/systemd/system 文件夾下面新建 nbddns.service 文件,將項目注冊成 Linux 服務,如下:

[Unit]
Description=nbddns
After=syslog.target network.target

[Service]
User=root
Group=root
Type=simple
WorkingDirectory=/home/pi/wol
ExecStart=/usr/dotnet/dotnet /home/pi/wol/HomeCloud.dll --urls "http://*:5100"

[Install]
WantedBy=multi-user.target

啟動 nbddns 服務,並設置開機自啟動,命令如下:

systemctl start nbddns.service && systemctl enable nbddns.service

查看服務狀態,如下圖:

最后,在路由器設置端口映射,然后通過域名和映射的外網端口訪問,我手機使用 4G 網絡,直接可以訪問到部署在樹莓派上面的 ASP.NET Core 應用,如下圖:



(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM