今回は、古いMacBook Proで動かしているUbuntu Serverに、異常が起きたらntfyで通知し、普段の状態も定期レポートで確認できる監視環境を作った。対象は、自宅サーバーとして動かしているUbuntu Server。SSH、Docker、Juice Shop、Tailscale、Fail2banなどがすでに動いている環境を前提に、監視を追加していった。
1. 通知先としてntfyを使う まず、サーバー側で異常を検知しても、そのままでは人間には分からない。そこで今回はntfyを使った。 Ubuntu Server ↓ 異常を検知 ↓ curlでntfy.shへ送信 ↓ Mac / iPhoneに通知 という流れ。テスト通知が届くことを確認してから、各監視に組み込んだ。ntfyのトピック名は公開せず、通知先の秘密情報に近いものとして扱う。
2. SSHへの不審なアクセスをFail2banで通知 すでに導入していたFail2banにntfy通知を追加した。Fail2banは、SSHログインを何度も失敗するIPなどを検知して、自動的にBANする仕組み。 今回は、 10分以内にSSHログインを5回失敗 ↓ Fail2banがIPをBAN ↓ ntfyで通知 という流れにした。テスト用IPを手動BANして、実際に通知が届くことも確認した。ここは1分ごとの監視ではなく、BANというイベントが起きた瞬間に通知する。
3. ディスク容量を1分ごとに監視 ルートディスク「/」の使用率を確認し、80%以上になったらntfy通知するようにした。ただし、異常状態が続いている間に毎分通知されると困るため、 異常発生 ↓ 1回通知 ↓ 異常中は追加通知しない ↓ 正常に戻ったら通知済み状態をリセット という仕組みにした。通知済みかどうかは「/tmp/」配下の小さな状態ファイルで管理している。
4. Docker / Juice Shop停止を監視 Docker上で動いているOWASP Juice Shopが停止していないかも監視した。 docker inspect ↓ runningか確認 ↓ 停止していたら通知 という仕組み。実際にJuice Shopを停止して通知を確認し、停止中にもう一度監視しても重複通知されないことを確認した。再起動後には通知済み状態もリセットされた。
5. CPU高負荷を監視 CPUは一瞬だけ90%になることもあるため、そのたびに通知するとノイズになる。そこで、 CPU 90%以上 ↓ 1分ごとに確認 ↓ 5回連続 ↓ 約5分間高負荷 ↓ 1回通知 という条件にした。CPU使用率はtopコマンドから取得した。 top -bn1 topの「id」はidle、つまりCPUが何もしていない割合なので、 CPU使用率 ≒ 100 - idle として計算する。テスト時はしきい値を一時的に低くして、5回目で通知されることを確認した。
6. メモリ高負荷を監視 メモリもCPUと同じ考え方で、90%以上が5回連続したら通知するようにした。 free -m で状態を確認したが、Linuxでは単純な「free」だけを見ると誤解しやすい。Linuxは空きメモリをキャッシュにも使うため、監視では「available」を基準にした。 available = アプリが必要になったとき、実際に利用できるメモリ と考えると分かりやすい。
7. Tailscaleの停止を監視 外部から安全に自宅サーバーへ接続するために使っているTailscaleも監視した。 tailscale status --json で状態を取得し、 BackendState: Running なら正常、それ以外なら異常として通知する。ただし、インターネット回線そのものが切れた場合はntfy.shにも到達できないため、その瞬間の通知はできない。この点は外部通知サービスを使う以上の制約になる。
8. AC電源が抜けたら通知 このサーバーはMacBookなので、内蔵バッテリーが簡易UPSのような役割を果たせる。AC接続状態は、 cat /sys/class/power_supply/ADP1/online で確認できる。 1 = AC接続中 0 = AC切断 実際にACアダプターを抜き、1から0に変化することを確認した。その状態で監視スクリプトを実行すると、AC電源が外れてバッテリー駆動になったという通知が届いた。
9. バッテリー残量を監視 バッテリー残量は、 cat /sys/class/power_supply/BAT0/capacity で取得できる。今回は2段階にした。 20%以下 → Battery Alert 10%以下 → CRITICAL Battery Alert 10%以下ではntfyのPriorityもurgentに設定した。テスト時は実際にバッテリーを10%まで減らすのではなく、しきい値を一時的に高くして通知動作を確認した。自動シャットダウンは誤作動時の影響が大きいため、今回は設定していない。
10. systemd timerで全部自動化 監視スクリプトは手動実行では意味がないため、systemd timerを使って1分ごとに自動実行するようにした。作った監視タイマーは、 ・ディスク監視 ・Docker監視 ・CPU監視 ・メモリ監視 ・Tailscale監視 ・AC電源監視 ・バッテリー20%監視 ・バッテリー10%監視 各タイマーで、 enabled = 再起動後も自動で有効 active (waiting) = 次回の実行時刻を待っている ことを確認した。
11. 1日3回のヘルスレポート 異常通知だけではなく、正常時の状態もまとめて確認できるようにした。レポート内容は、 ・CPU使用率 ・メモリ使用率 ・Load Average ・ディスク使用率 ・Juice Shop ・Tailscale ・Fail2ban ・AC電源 ・バッテリー ・インターネット接続 ・Uptime 送信時刻は08:00、14:00、22:00の1日3回。実際にntfyへ、 CPU: 4.7% Memory: 18.7% Disk: 3% Juice Shop: running Tailscale: Running Fail2ban: active AC Power: Connected Battery: 80% Internet: Online Uptime: ... のようなレポートが届くことを確認した。Dockerの状態取得には権限が必要だったため、ヘルスレポート用のsystemd serviceだけrootで実行している。
12. 最後に全体点検 監視を1個ずつ確認するのは面倒なので、まとめて確認した。 systemctl list-timers --all | grep -E 'check-|health-report' これで監視タイマーとヘルスレポートの次回実行時刻を一覧表示できる。 systemctl --failed では失敗中のsystemd unitを確認できる。今回の結果は、 0 loaded units listed. となり、systemd上では失敗中のサービスはゼロだった。
今回学んだこと 今回一番大きかったのは、個別のLinuxコマンドではなく、監視システムの基本構造を理解できたこと。 状態を取得する ↓ 正常 / 異常を判定する ↓ 異常なら通知する ↓ 同じ異常を何度も通知しない ↓ 正常に戻ったら状態をリセットする ↓ systemdで自動実行する この考え方は、ディスクでもCPUでもバッテリーでもほぼ共通している。
また、 systemd systemctl Shell Script /sys /tmp Docker Fail2ban Tailscale curl ntfy といった技術が、それぞれ別々に存在するのではなく、組み合わせることで1つの監視システムになることも理解できた。
今回作った環境は小規模な自宅サーバー監視だが、考え方としてはPrometheus、Grafana、Wazuhなどの本格的な監視・SOC環境にもつながっていく。