家のサーバーに自分専用のトップページを作り、ToDo・サーバーの状態・サービスの稼働をひと目で見られるようにした
家のサーバーで動いているサービスが増えてくると、「いま全部ちゃんと動いているか」「サーバーに余裕はあるか」を確かめるだけで、いくつもの画面を開くことになります。そこで、ブラウザで開くだけで、今日の ToDo・サーバーの状態・各サービスの稼働状況がひと目で分かる“自分専用のトップページ”を家のサーバーに作りました。
できあがった画面

- 左:今日の ToDo・プロジェクトの未完了の ToDo(Obsidian のノートから自動で取り込み)
- 右上:家のサーバーと AWS のサーバーの負荷・メモリ・ディスク・起動してからの時間、Mac のディスクの空き
- 右下:各サービスの稼働状況。緑の点が付いていれば正常で、クリックするとその管理画面が開く
- 下:家族が書き込める共有のメモ欄
- 右上には時計。ロゴも付けて、ちょっとした「家のポータル」の気分です
仕組み

ページ本体は1枚の index.html で、表示に必要なデータはすべて JavaScript の fetch で読み込んでいます。データを作る部分を役割ごとに小さく分けたので、どこかが止まってもページ全体は壊れません。
| 表示 | データの出どころ | 更新の間隔 |
|---|---|---|
| サービスの稼働状況・サーバーの状態 | status.php(PHP で各サービスに接続して確認) | 1分ごと |
| AWS のサーバーの状態 | AWS 側の小さなページ(JSON)を status.php が取りに行く | 1分ごと |
| ToDo | Mac の Obsidian のノート → サーバーが取りに行って todo.json に保存 | 15分ごと |
| Mac のディスクの空き | 同じ仕組みで Mac から取得 | 1日1回 |
| 共有メモ | memo.php(読み出しと保存) | 1分ごとに読み直し |
1. サービスの状態を調べる status.php
各サービスに実際に接続してみて、応答があるか・何ミリ秒かかったかを JSON で返します。下は考え方を示すための簡略版です。
<?php
header('Content-Type: application/json');
// 確認したいサービス(名前 => URL)
$targets = [
'blog' => 'http://127.0.0.1/blog/',
'cacti' => 'http://127.0.0.1/cacti/',
];
$out = ['checked_at' => date('c'), 'services' => []];
foreach ($targets as $name => $url) {
$t = microtime(true);
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_NOBODY => true, CURLOPT_TIMEOUT => 3, CURLOPT_RETURNTRANSFER => true]);
curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$out['services'][$name] = ['state' => ($code >= 200 && $code < 400) ? 'up' : 'down',
'code' => $code, 'ms' => (int)((microtime(true) - $t) * 1000)];
}
// サーバー自身の状態(負荷・メモリ・ディスク)
$out['server'] = ['load' => sys_getloadavg(), 'disk_free' => disk_free_space('/')];
echo json_encode($out);
- Web 以外(データベース・NAS・ルーターなど)は、TCP で接続できるかだけを見る(
fsockopen) - メモリは
/proc/meminfo、起動してからの時間は/proc/uptimeから読む - タイムアウトは短く(数秒)。1つのサービスが固まっていても、ページ全体が待たされないようにする
2. AWS のサーバーの状態も並べる
AWS のサーバーにも、負荷・メモリ・ディスクを JSON で返す小さなページを置きました。このページは家の IP アドレスとサーバー自身からしか開けないようにしてあり、家のサーバーの status.php が1分ごとに取りに行きます。これで、家と AWS の両方の状態を同じ画面で比べられます。
3. ToDo は Obsidian のノートから自動で取り込む
日々のメモやプロジェクトの記録は Obsidian で書いています。そのノートから、次の2つを自動で拾ってトップに出すようにしました。
- 今日の ToDo:前日の日次ノートの「明日の TODO」の項目
- プロジェクトの未完了の ToDo:各プロジェクトのノートの「## TODO」にある、チェックの付いていない項目(
- [ ])
ノートを読む Python のスクリプトは Mac 側に置き、家のサーバーが15分ごとに SSH で取りに行く形にしました。逆向き(Mac からサーバーへ送る)にしなかったのには理由があります。
- Obsidian の保管場所は Google ドライブの中にあります。macOS の保護機能のため、Mac の自動実行(launchd)からは Google ドライブの中を読めませんでした
- 読めるようにするには「フルディスクアクセス」という強い許可が必要で、そこまではしたくなかった
- サーバーから SSH で呼び出せば、普通のログインと同じ扱いになり、追加の許可なしで読めました
ただし、サーバーの鍵で Mac に何でもできてしまうのは困ります。そこで Mac 側の authorized_keys で、その鍵で実行できるコマンドを1つだけに制限しています(書き方の説明)。
# Mac の ~/.ssh/authorized_keys(1行で書く)
restrict,command="/usr/bin/python3 /Users/ユーザー名/bin/vault_todo_export.py --stdout" ssh-ed25519 AAAA…(サーバーの公開鍵)
# 家のサーバーの crontab(15分ごと)
*/15 * * * * $HOME/bin/fetch_todo.sh
fetch_todo.sh は、受け取った JSON に今日の ToDo が入っているときだけ todo.json を置き換えます。Mac が寝ていたり電源が切れていたりしても、前回のデータが表示され続けます。ページには最終更新の時刻を出し、1時間以上更新が止まっていたら「Mac が止まっている可能性」と表示します。
同じ仕組みを使って、Mac のディスクの空き容量も1日1回取り込み、26時間以上更新がなければ「更新が止まっています」と出すようにしました。
4. 家族で使える共有メモ
ページの一番下には、誰でも書き換えられるメモ欄を2つ置きました。買い物のメモや、家族への伝言に使っています。
memo.phpが、読み出し(GET)と保存(POST)を JSON でやり取りする- 保存先は Web の公開フォルダの外。上書きの直前の内容を1つだけ残すので、うっかり消しても戻せる
- 最大 5,000 文字。1分ごとに読み直すが、入力中は読み直さない(書きかけが消えないように)
- ログインは付けていない。ページ自体が家の中(VPN を含む)からしか開けないため
5. 見た目の工夫
- パソコンでは2列、スマホでは1列に自動で並び替える(CSS の grid とメディアクエリ)
- パソコンやスマホがダークモードのときは、暗い配色に自動で切り替える(
prefers-color-scheme)。ロゴの文字色もページの文字色に合わせる - サービスの一覧は、状態に応じて点の色を緑・黄・赤に変える
- 検索エンジンに載らないよう、
noindexを付けておく(そもそも外からは見えないが念のため)
安全に使うために
- ページと status.php・memo.php は、家の中(VPN を含む)からしか開けないようにする。外に公開する場合は、必ずログインを付ける
- status.php の確認先は、プログラムの中に書いたものだけにする(URL を外から渡せるようにすると、サーバーを踏み台にされる恐れがある)
- SSH で Mac を呼び出す鍵は、実行できるコマンドを1つに絞る
まとめ
朝いちばんにこのページを開けば、「今日やること」と「家のサーバーと AWS の調子」が一度に分かるようになりました。異常があれば Uptime Kuma からメールも届きますが、普段の安心感はこのページのおかげです。1枚の HTML と小さな PHP・スクリプトの組み合わせなので、自宅サーバーをお持ちの方なら、自分好みのポータルとして気軽に作れると思います。
