こんにちは、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 mainimport ( "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インターネットグループの採用ページ をご覧ください。きっとあなたのやりたいことが見つかると思います。