目次
はじめに
サーバー停止時にお知らせを表示させる仕組みを構築した。
YAMAHAルーターのLUA機能を利用して定期的なping実行でホストの稼働監視をさせて,一定期間応答が無い場合にお知らせ画面に誘導する。ping応答が回復したら通常画面に戻る。
ping監視のひな形はヤマハホームページに載っていたので難なく構築できた。
ホストを監視する (yamaha.com)
当初はルーターのカスタムGUI機能を利用して外部からルーターのお知らせ画面にアクセスする方法を検討したが,ベーシック認証のポップアップ画面を回避できず,またルーターの管理画面へアクセスされる懸念もあり断念して,LAN内の別サーバーにお知らせ画面を置くこととした。
当初案
ルーターにお知らせ画面を配置する際の検討結果
定期的にPING監視して,一定回数応答がなかったらカスタムGUIの無名ユーザ画面にアクセスさせるためrt.commandでWEBポートのIPマスカレードCONFIG設定を自ルーターのIPアドレスに変更する。カスタムGUIの無名ユーザ画面は「サーバー停止のお知らせ」を表示する。
PING応答が復活したらIPマスカレードCONFIG設定を戻す。
ルーターにお知らせ画面を置く際の問題点
① 外部から80ポートで直接アクセスできない仕様となっており,別ポートを経由してアクセスすることになる。
ルーターのhttp待ち受けポートを標準の80から変更する(例 80>>>8888)
rt.command(“httpd listen 8888”) にして外部80をnat で8888 に変更
rt.command(“nat descriptor masquerade static 1 2 192.168.0.1 tcp www=8888”)
② 無名ユーザでパスワード指定なしの場合はベーシック認証画面は空白でエンターすればお知らせ画面が表示される。無名では設定guiに入れない。
ただしベーシック認証画面で正しいユーザーとパスワードを入力すれば管理画面に入れるのでセキュリティー上好ましくない。ルーターにお知らせ画面を置くのは難しい。
無名ユーザの場合はconfig設定でユーザ名を省略して,「directory=」のフォルダーにのみアクセス可能
# httpd custom-gui user directory=/gui/anonymous
代替案
ルーターにお知らせ画面を置くのをあきらめて,LAN内の未使用サーバーに置くこととする。前世代で使用していたサーバーTX100S3を活用してフォルダー構造が同じなので,ドキュメントルート直下のメンテナンスフォルダーにhtmlで作成した画面を置く。(index.html)
代替サーバーのデフォルトゲートウェイは本番サーバーと同じに設定。フォルダー構造も本番サーバーと同じに設定する。
【参考】フォルダー構造のみコピーするコマンド
dドライブのフォルダー「www」以下のサブフォルダーをfドライブにコピー
xcopy /e /i /t d:\www f:\www
本番サーバー停止時に代替サーバーをWOL起動させて,ルーターのnat設定を代替サーバーに変更する。本番サーバー停止から代替サーバーに切り替わる際に数分のタイムラグがあり,その際にエラー画面が表示されるが自動切換えなので仕方ない。事前に代替サーバーを起動しておいて手動でconfig設定すればエラー画面は表示されない。
本番サーバー復旧時は逆の動作で切り替わる。代替サーバーは稼働したままとなるが,本番サーバーのスタートアップでbatファイルから代替サーバー停止のコマンド「PsShutdown」を投入することで停止できる。
【参考】パソコンの起動・停止監視ツール – na-blog (na-3.com)
リダイレクト設定
代替サーバーのドキュメントルートに.htaccessファイルを置いてルートディレクトリ以下をお知らせ画面ページへリダイレクトさせる。
配下のディレクトリに.htaccessファイルがあるとそちらが優先されるので,リネーム等で無効にしておく。
# メンテナンス画面へリダイレクト (ドキュメントルートに配置)
ErrorDocument 503 /maintenance/index.html
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_URI} !=/maintenance/index.html
RewriteRule ^.*$ - [R=503,L]
</IfModule>
## メンテ終了予定時刻を指定
#<IfModule mod_headers.c>
# Header set Retry-After "Sat, 27 Apr 2024 6:00:00 GMT"
#</IfModule>
実際の設定
配置したドキュメントルート以下の全てのフォルダー・ファイルを「https://hoge.com/maintenance/index.html」のお知らせ画面ファイルへ一時的にリダイレクトする。しかし長期間停止していたのでssl証明書が期限切れでhttp接続限定となり警告が表示される。お知らせ画面の表示だけなのでこれでもよいのだが,事前に期限切れ前に定期的に起動してssl証明書を取得するか,またはwol起動時にしばらく放置で取得するかどちらかが必要。
お知らせ画面例
代替サーバーのドキュメントルート直下のリダイレクト先フオルダー(maintenance)に置く。
(例:D:\www\public_html\maintenance\ 又は D:\www\a-blog\maintenance\)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title>サーバーメンテナンスのお知らせ</title>
<h2>サーバーメンテナンスのお知らせ</h2>
<p>ただいまサーバーのメンテナンスを実施しています。
<br>
<br>
停止に伴い、下記の通りホームページの閲覧および全サービスを一時休止いたします。
<br>
誠に申し訳ございませんが、ご了承くださいますようお願い申し上げます。
<br>
<br>
■ホームページの閲覧およびサービスの休止
<br>
<br>
ホームページ ブログサイト (<a href="https://hoge.com/hoge-blog/">https://hoge.com/hoge-blog/</a>)
<br>
<br>
その他 hoge.comドメインの全ページ
<br>
<br>
メールサーバー @hoge.com
<br>
<br>
※現在,復旧に向けて全力で対応しております。今しばらくお待ちください。_(._.)_
</p>
</head>
</html>
ルーターconfigの変更
事前変更・追加箇所
フィルター定義の変更は若干セキュリティーを緩める方向だが,luaでの書き換えを少なくするため実施。
サーバー稼働監視のluaをルーター起動と共に起動させるため,スケジュール設定追加。
#フィルター定義のサーバーipアドレス設定をネットワークに変更例 他にも同様変更あり
ip filter 1031 pass * 192.168.0.100 tcpflag=0x0002/0x0017 * www
ip filter dynamic 201 * 192.168.0.100 www
↓
ip filter 1031 pass * 192.168.0.0/24 tcpflag=0x0002/0x0017 * www
ip filter dynamic 201 * 192.168.0.0/24 www
#スケジュール設定
#サーバー停止のお知らせ監視 <<<<<<<<<<<< 追加
schedule at 3 startup * lua /lua/server-check.lua
サーバー停止時の自動変更箇所
ルーターconfigの変更はLUAスクリプト(server-check.lua)で自動書き換えする。
本番サーバー停止時
nat descriptor masquerade static 1 2 (代替サーバーipアドレス) tcp www
nat descriptor masquerade static 1 6 (代替サーバーipアドレス) tcp https
本番サーバー復旧時
nat descriptor masquerade static 1 2 (本番サーバーipアドレス) tcp www
nat descriptor masquerade static 1 6 (本番サーバーipアドレス) tcp https
ルアスクリプト
ルーターで常時動作させるルアスクリプト。(server-check.lua)
ヤマハホームページのひな形を利用して,追加変更(ハイライト部)はわずかで完成した。
Windows Updateで再起動する際に更新時間が長い場合は一旦,代替サーバーに切り替わることがある。通常の再起動を何度か行って監視間隔・回数を40秒・5回にした。機種によりその値は調整が必要。
--[[
●ping 応答監視スクリプト
指定したアドレスに宛に ping を実行してその応答を監視し、応答がなかった場合
に管理者にメールを送信とホームページ閲覧者にサーバー停止のお知らせを表示して
知らせるスクリプトです。
指定した回数連続して ping に対する応答がなかった場合には、管理者にメールを
送信して知らせます。その後、指定した回数連続して応答があった場合には、応答
が回復したと判断します。設定値 down_mail を true に設定している場合には、応
答が回復した際にもメールを送信します。
<説明>
・このファイルを RTFS か外部メモリに保存してください。
・本項目の config の設定では schedule at コマンドでルーター起動時に Lua スク
リプトが実行されるように設定しています。
・スクリプトを停止するときは terminate lua コマンドを実行してください。
・再度、Lua スクリプトを実行する場合は lua コマンドで実行してください。
・★マークの付いた設定値は変更が可能です。
・☆マークの付いた設定値はヤマハ標準からの変更箇所です。
<ノート>
・メールの送信失敗時に出力する SYSLOG レベルを指定可能です。
SYSLOG のレベルを指定するには、log_level を設定してください。
debug レベル、notice レベルの SYSLOG を出力するためには、それぞれ以下の設定
が必要です。
debug レベル ・・・ syslog debug on
notice レベル・・・ syslog notice on
・本スクリプトファイルを編集する場合、文字コードは必ず Shift-JIS を使用してく
ださい。
]]
--------------------------## 設定値 ##--------------------------------
-- 監視間隔(1 - 864000 秒)
idle_time = 40 -- ★ 40秒毎に本番サーバーを監視
-- ping への応答がない、または応答が回復したと判断する連続回数(1, 2 ..)
count = 5 -- ★ 40秒毎に5回監視して200秒(3分20秒)間停止・起動していたら代替・本番サーバーへ切替
-- 応答が回復したときにもメールを送るかどうか(送る: true / 送らない: false)
down_mail = true -- ★
-- メールの送信に失敗したときに出力する SYSLOG のレベル(info, debug, notice)
log_level = "info" -- ★
-- ping を実行する宛先 IP アドレス
dst = "192.168.0.100" -- ★ 監視サーバーipアドレス
-- ☆ 停止お知らせ画面の代替えサーバーIP アドレス MACアドレス
alt = "192.168.0.200" -- ☆ 代替サーバーipアドレス
targetmac3 = "00:11:22:33:44:55" -- ☆ 代替サーバーmacアドレスlan3 dmz
targetmac1 = "00:22:33:44:55:66" -- ☆ 代替サーバーmacアドレスlan1
targetip = "" -- ☆ NATipアドレス
-- メールの設定 -- ☆
mail_tbl = {
smtp_address = "hoge.net", -- 自分のメールサーバー
smtp_port = "587", -- "25" | "587"
smtp_auth_name = "rt@hoge.net", -- 自分のメールサーバーアカウント
smtp_auth_password = "password", -- 自分のメールサーバーパスワード
pop_before_smtp = true, -- true | false
pop_address = "hoge.net", -- 自分のメールサーバー
pop_protocol = "pop3", --
pop_auth_name = "rt@hoge.net", -- POP認証用ユーザー名
pop_auth_password = "password", -- POP認証用パスワード
from = "RTX1210@hoge.com", -- 送信元アドレス
to = "rt@hoge.net" -- 宛先アドレス
-- subject = "", -- 件名 (処理中に代入)
-- text = "" -- 内容 (処理中に代入)
}
----------------------## 設定値ここまで ##----------------------------
------------------------------------------------------------
-- ping を実行し、到達したかどうかを返す関数 --
------------------------------------------------------------
function ping_reach(adr)
local rtn, str, loss
local reach = false
local cmd = "ping " .. adr
local ptn = "(%d+)%.%d+%%"
rtn, str = rt.command(cmd)
if (rtn) and (str) then
loss = str:match(ptn)
if (loss) then
loss = tonumber(loss)
if (loss == 0) then
reach = true
end
end
end
return rtn, reach, str
end
--------------------------------------------------------------
-- 連続何回 ping に応答がないかを示すカウンターの処理関数 --
--------------------------------------------------------------
function count_proc(t, reach, th)
local rtn = 0
if (not reach) then
if (not t.flag) then
t.ng = t.ng + 1
if (t.ng == th) then
rtn = 1
t.flag = true
end
else
if (t.ok > 0) then
t.ok = 0
end
end
else
if (t.flag) then
t.ok = t.ok + 1
if (t.ok == th) then
rtn = -1
t.flag = false
t.ng = 0
t.ok = 0
end
else
if (t.ng > 0) then
t.ng = 0
end
end
end
return rtn
end
------------------------------------------------------------
-- メール本文を作成する関数 --
------------------------------------------------------------
function make_pingmsg(tbl, reach, adr, cnt, sec, down)
local rtn
local str = ""
rtn = count_proc(tbl, reach, cnt)
if (rtn < 0) then
if (down) then
str = "pingの応答が回復しました。\r\n"
str = str .. string.format(" 送信先: %s\r\n 監視間隔: %d(秒)\r\n\r\n",adr, sec)
targetip = dst -- ☆ 本番サーバーipアドレスに戻す
end
elseif (rtn > 0) then
str = "pingの応答がありません。\r\n"
str = str .. string.format(" 送信先: %s\r\n 応答がなかった回数: %d回\r\n 監視間隔: %d(秒)\r\n\r\n",adr, cnt, sec)
targetip = alt -- ☆ 代替サーバーipアドレスに設定
end
return str
end
------------------------------------------------------------
-- 現在の日時を取得する関数 --
------------------------------------------------------------
function time_stamp()
local t
t = os.date("*t")
return string.format("%d/%02d/%02d %02d:%02d:%02d", t.year, t.month, t.day, t.hour, t.min, t.sec)
end
------------------------------------------------------------
-- 代替サーバーの起動 -- ☆
------------------------------------------------------------
function altserver_start()
rt.command("wol send lan3 " .. targetmac3)
rt.sleep(1)
rt.command("wol send lan1 " .. targetmac1)
end
------------------------------------------------------------
-- サーバーのルート変更config -- ☆
------------------------------------------------------------
function server_route()
rt.command("nat descriptor masquerade static 1 2 " .. targetip .. " tcp www")
rt.command("nat descriptor masquerade static 1 6 " .. targetip .. " tcp https")
end
------------------------------------------------------------
-- メインルーチン --
------------------------------------------------------------
local rtn, reach, str
local reach_tbl = {ng = 0, ok = 0, flag = false}
while (true) do
mail_tbl.text = ""
rtn, reach, str = ping_reach(dst)
if (rtn) then
mail_tbl.text = mail_tbl.text .. make_pingmsg(reach_tbl, reach, dst,count, idle_time, down_mail)
else
mail_tbl.text = string.format("%s (ping送信先: %s\r\n\r\n)", str, dst)
end
if (mail_tbl.text:len() > 0) then
mail_tbl.subject = string.format("watch ping : %s (%s)", dst, time_stamp())
rtn = rt.mail(mail_tbl)
server_route() -- ☆ ルーターのconfig変更
if targetip == alt then -- ☆ 代替サーバー起動
altserver_start() -- ☆ 代替サーバー起動
end -- ☆ 代替サーバー起動
if (not rtn) then
rt.syslog(log_level, "failed to send mail. (server-check.lua)")
end
end
rt.sleep(idle_time)
end
代替サーバー停止
本番サーバー復旧時に代替サーバーを停止するため,本番サーバーのスタートアップに下記batファイルを登録してPsShutdownコマンドを投入する。
代替サーバーの起動有無に関係なく実行する。
rem 5分後にipアドレスで指定したpcを停止 server-stop.bat
timeout /t 300
PsShutdown64 -s \\ipアドレス [ -u user -p psswd]
Windows 8.1以降・Windows Server 2012 およびそれ以降で対応している。
当環境ではWindows Server 2008R2で動作した。
Windows 7 Proでもポート開放「Netlogonサービス(NP受信)ポート:445」で動作するが,下記のエラーを表示する。その後再起動・停止処理に入る。PHPからのコマンド投入は動作しない。
おわりに
当初案のルーターにお知らせ画面を置く構想は捨てきれていないが,試していない方法があるのかも。今後の課題として取っておくことにする。長期停止の際に代替サーバーに代えてマイクロPC(ベアボーンPC)がジャンク品の中にあったのでそれを利用する方法もありかも。電気代が気になるので今後検討するか。
ちなみにサーバーをメンテナンスモードにする際には,pingに応答しないようにすればよいのでDMZ回線のLAN2ネットワークアダプターを無効にするか又はLAN2ケーブルを抜けばよい。後者のほうが簡単。メンテナンスはLAN1回線又はiRMC回線から行える。