UbuntuとGo言語で作るWOL API サーバー

こんにちは、GMOインターネットグループ株式会社の長谷川です。
今回はWindowsに対してUbuntuサーバーからWake-on-LANを遠隔で行えるAPIサーバー構築に関してお話して行こうと思います。

作成動機

電気代が上がっているので自宅の VPN サーバーを使用時以外は出来るだけ休止させて
おきたいという熱い思いからです。

WOLとは

Wake-on-LANと呼ばれる技術の略称で、主にLAN内のNWに繋がっているPC等に
マジックパケットというパケットを送り電源投入を行う技術です。

システム構成

簡単にまとめてしまうと、自宅外から自宅内の Ubuntu の API サーバーに向け API を叩きます。
target の PC に向け Ubuntu の API サーバーから WOL コマンドを実行しマジックパケットを発行します。

Windows の ACPI ステートに関して

WOLを利用する場合にはWindowsのバージョンやハードウェア構成により、起動できるACPIのステートが異なる場合があります。

ACPIステートは以下の状態があります。

ACPI ステート状態
S0 (動作中)システムが完全に使用出来る状態、稼働中
S1 (スリープモダンスタンバイ)低電力アイドル状態、CPUクロック停止、HDDの回転停止、メモリ保持
S2 (スリープモダンスタンバイ) 低電力アイドル状態、CPUクロック停止、HDDの回転停止、メモリ保持
S3 (スリープモダンスタンバイ) 低電力アイドル状態、CPUクロック停止、HDDの回転停止、メモリ保持
S4 (休止状態) 低電力アイドル状態、CPUクロック停止、HDDの回転停止、ファイル保持
S5 (シャットダウン) 完全なシャットダウン
引用元 : https://learn.microsoft.com/ja-jp/windows/win32/power/system-power-states

今回は S4 休止状態からの起動を想定して API サーバーを作成します。
ここでは Windows 側の設定の例は様々なパターンがあるため、それぞれの環境に合わせ設定されている想定として以後進めていきます。

Ubuntuサーバーの環境構築

Go言語はクロスコンパイルが可能でシングルバイナリとしても配置できる為、
Ubuntuサーバーに合わせてビルドが出来るようであれば
Ubuntuサーバーに必要なものは、WOLコマンドの実行出来れば問題ありません。

sudo apt install wakeonlan

実際のAPIサーバーのコード

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os/exec"
    "regexp"

// 今回は軽量Web toolキットの gorilla mux を使います。
// ビルド環境にない場合には "go get -u github.com/gorilla/mux" でインストールしてください
    "github.com/gorilla/mux"
)

type Device struct {
    MacAddr string `json:"macaddr"`
}

// 入力された MAC アドレスを元に WOL コマンドを実行する関数
func InputWOLCommand(macaddr string) string {
    out, _ := exec.Command("wakeonlan", macaddr).Output()
    return string(out)
}

// API の Postを受け取る関数
func postWOL(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    var wol Device
    _ = json.NewDecoder(r.Body).Decode(&wol)
// 送られてきた MAC アドレスが本当に MACアドレスの形式になっているか正規表現でチェックする。
    regTrueFalse, _ := regexp.MatchString("(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}", wol.MacAddr)
    if regTrueFalse {
// MACアドレスが正しい形式であればWOLコマンドを実行する関数にMACアドレスを引き渡します。
        out := InputWOLCommand(wol.MacAddr)
        json.NewEncoder(w).Encode(wol)
        fmt.Println("wol wake up server -> " + out)
    } else {
        fmt.Println("Not match MAC type")
    }
}

func main() {
// ルーターのイニシャライズ
    r := mux.NewRouter()
    fmt.Println("Port UP : 3000")

// ルーティングと起動ポートの指定
    r.HandleFunc("/api/wol/", postWOL).Methods("POST")
    log.Fatal(http.ListenAndServe(":3000", r))
}

上記をビルドして Ubuntu サーバーに配置します。
systemd にサービス登録などの手順は省きますが、配置が完了したら起動して
自宅のルーターにポート転送やファイヤーウォールの設定を行い、グローバルIPからAPIサーバーのポートにアクセスできるようにします。(ルーターの説明書やウェブページを検索すると手順が書かれた記事が数多くあります。。)

実行

APIを叩くことが出来れば何でもよいですが今回は curl で投げます。

curl -X POST -H "Content-Type: application/json" -d "{\"macaddr\":\"[起動設定させたPCのMACアドレス]\"}" "http://[自宅グローバルIP]:3000/api/wol/"

target PC が熱い思いにより起動されると成功です。

まとめ

APIがないものにAPIを生やしたいという熱い思いや、遠隔で操作を行いたい、
自動化が好きだという方は是非 GMOインターネットグループの採用ページ をご覧ください。
きっとあなたのやりたいことが見つかると思います。

ブログの著者欄

長谷川 泰斗

GMOインターネットグループ株式会社

2020年 GMOインターネットグループ株式会社 新卒入社
クラウド基盤エンジニア
お名前.com KVM, ConoHa VPS等の開発運用に従事

採用情報

関連記事

KEYWORD

採用情報

SNS FOLLOW