嫁ちゃん
わたし
嫁ちゃん
わたし
コンテナは「Up」なのに、外からは見えない #
自宅のM1 Mac miniにMinIOを立て、公開用と非公開用のバケットを綺麗に仕分け直した。 重たい画像はすべて自宅サーバーのオブジェクトストレージへ逃がし、手元のObsidianは身軽なテキストだけの同期に戻る。悩まされていた同期容量の制限から解放され、私の自宅Webサーバー運用はいよいよ完成形に近づいたと、すっかり満足していた。
だが、仕組みが実稼働に入って間もなく、またしても冷や汗をかくような小さな問題が顔を覗かせ始めた。
妻の言うとおり、iPhoneや外出先のMacから自分のブログ(okadai.me)を開こうとすると、ごく稀にブラウザが白く立ち往生し、Cloudflareの無機質なエラー画面が表示されるのだ。
画面の中央には、大きく「Error 1033 Argo Tunnel error」という文字。 HTTPステータスコードで言えば「530」や、接続タイムアウトを示す「000」である。
慌てて自室のMacからM1 Mac miniにSSHでログインし、Dockerコンテナの状態を確かめる。
docker psターミナルに返ってきた結果を見て、私は思わず首を傾げた。
Cloudflareとの暗号化トンネルを中継している hugo-tunnel(cloudflared)コンテナのステータスは、何事もなかったかのように「Up(稼働中)」のままなのだ。
コンテナがクラッシュしたわけでも、メモリ不足で強制終了したわけでもない。プロセス自体は平然と息をしている。 だが、外のインターネット世界と自宅を繋ぐトンネルのセッションだけが、何らかの拍子に切断され、内部でハングアップしてしまっていたのだ。
Docker Composeで設定している restart: unless-stopped は、「コンテナ内のプロセスが異常終了(exit)したとき」に初めて再起動をかけてくれる仕組みだ。
つまり、プロセス自体が「Up」のまま黙り込んでいる限り、Docker側からは正常に動いているように見え、いつまで経っても自動再起動の引き金が引かれない。
これが、自宅サーバーとトンネル技術を組み合わせたときに直面する、厄介な「静かな沈黙」だった。
ベストエフォート回線の限界なのか、という葛藤 #
この現象は、一度きりの偶然ではなかった。 日に数回、あるいは忘れた頃にふっと発生する。
実のところ、cloudflared にも自己再接続の機能は備わっている。だが、回線の瞬断などを検知したあと、内部で段階的バックオフ(指数関数的な再試行待機)に入ってしまう性質があるらしい。その結果、自動で復旧するまでに3分から5分ほどの「空白の時間」が生じてしまう。
手動で直すのは簡単だ。ターミナルから docker restart hugo-tunnel と叩けば、わずか2〜3秒で新しいトンネルが張り直され、サイトは瞬時に息を吹き返す。
だが、公開しているWebサイトが見えない状態が何分間も続くというのは、運営者として決して気持ちのいいものではない。
「もしかして、これが自宅サーバーの限界なのだろうか」 ( Geminiさんには、クラウドフレアページ(どんなサービスか知らないが)ここに、サイトを置いておけば、こんなエラーからは解放されるんだよと、何度もご提案をいただいたが、せっかくレンタルサーバーを解約手続きをして、自宅からの発信にしたいと思っていたのに、その気持ちはGeminiさんには伝わらなかったのだろうか )
デスクの片隅で静かに佇むM1 Mac miniを見つめながら、そんな考えが頭をよぎった。 データセンターにある堅牢なサーバーと違い、ここは一般家庭の居間だ。引いている光回線も、帯域が保証されていない「ベストエフォート」のコンシューマー回線である。どれだけ機材を揃えても、家庭用回線と無料のCloudflare Tunnelを組み合わせた自宅運用には、越えられない安定性の壁があるのかもしれない。
そんな不安が、胸の奥をチリチリと焦がす。
かといって、ここで月額数千円もする外部の商用監視サービス(SaaS)を契約したり、サーバー内に重たい死活監視コンテナ(autohealなど)を常駐させたりするのは、私の「引き算の運用美学」に反する。 管理する道具を減らし、日々の暮らしに余白を取り戻すために自宅サーバーを組んだのに、その監視のためにまた別のシステムを抱え込んでしまっては本末転倒だ。
道具を増やすのではなく、今ある仕組みの手入れでどうにかできないか。 元プログラマーとしての血が、静かに騒ぎ始めた。

「二度肩を叩く」——小さなシェルスクリプトによる自己復旧 #
要するに、外の世界から見て「通じているかどうか」を定期的に確かめ、死んでいるなら叩き起こしてやればいい。
大掛かりな監視ツールなど要らない。M1 Mac miniのホスト側から、自分自身の公開URL(https://okadai.me/)に向けて、数分おきに curl を一発投げるだけで事足りる。
ただし、そこには一つだけ大切な工夫が必要だった。 「1回の失敗ですぐに再起動をかけない」ということだ。
ベストエフォート回線である以上、近所のトラフィックの急増や、Wi-Fiの瞬間的な電波の揺らぎで、1秒だけパケットが詰まることくらい日常茶飯事だ。そんな些細な瞬断のたびにトンネルを再起動していては、かえって接続を不安定にしてしまう。
そこで私は、「2回連続で異常を検知したときだけ再起動する」という、二重チェックのロジックを組んだ。
#!/bin/bash
TARGET_URL="https://okadai.me/"
LOG_FILE="$HOME/Library/Logs/tunnel-keepalive.log"
# 1回目の確認(タイムアウト10秒)
HTTP_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 10 "$TARGET_URL")
# 530(Tunnel Error)、000(不通)、または500番台エラーを検知
if [ "$HTTP_STATUS" = "530" ] || [ "$HTTP_STATUS" = "000" ] || [ "$HTTP_STATUS" -ge 500 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 異常検知 (HTTP $HTTP_STATUS) -> 3秒後に再確認..." >> "$LOG_FILE"
sleep 3
# 2回目の確認(リトライ)
RETRY_STATUS=$(curl -k -s -o /dev/null -w "%{http_code}" --max-time 10 "$TARGET_URL")
if [ "$RETRY_STATUS" = "530" ] || [ "$RETRY_STATUS" = "000" ] || [ "$RETRY_STATUS" -ge 500 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 再確認でも異常 (HTTP $RETRY_STATUS) -> トンネルを強制再起動" >> "$LOG_FILE"
docker restart hugo-tunnel >> "$LOG_FILE" 2>&1
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 一時的な瞬断でした。復旧確認 (HTTP $RETRY_STATUS)" >> "$LOG_FILE"
fi
fiまるで、朝なかなか起きてこない家族の部屋のドアを叩くようなものだ。 「おーい、起きてるか?」と一度声をかけ、返事がなければ3秒待って「ほんまに寝てるな?」ともう一度肩を揺らす。それでも起きなければ、布団を剥ぎ取って叩き起こす。
このたった数十行のシェルスクリプトを、macOS標準の常駐機構である launchd に登録し、5分間隔で静かに巡回させることにした。
異常の気配は、Obsidianの画面で静かに受け取る #
もう一つのこだわりは、「異常が起きたときの通知」のあり方だ。
再起動のたびにスマートフォンへけたたましいプッシュ通知を飛ばすような真似はしたくない。生活のノイズを増やしたくないからだ。
だが、サーバーがいつ寝ぼけて、いつ自律的に復旧したのかという履歴は、どこかで把握しておきたい。
(エラーが来ることに慣れてしまって、サイトが沈黙しているのを黙認していたりした)
そこで、トンネルの再起動が走った際、M1 Mac mini上のスクリプトがObsidianのタスク管理ノート(02_Area/Tasks.md)へ、自動的に1行のタスクを追記するように仕組んだ。
- [x] #task #inbox ⚠️ okadai.me 異常検知: HTTP 530 (10:22) [priority:: highest]このタスクは、Obsidian Syncを通じて手元のMacBookやiPhoneのデイリーノート、タスク一覧画面へと静かに同期される。
日々の作業の合間や、朝のモーニングページを書くときにObsidianを開くと、「ああ、今朝の10時過ぎに一度回線が詰まって、自動で起き上がってくれたんだな」とひと目でわかる。 タスクを確認したら、完了チェックを入れるだけで記録として消えていく。
サーバーの監視ログをわざわざ黒い画面(ターミナル)を開いて漁る必要はない。 日々の思索や生活のメモを綴っている、いつものノートの上に、サーバーの状態もひとつの生活ログとして穏やかに同居している。

手のかかる道具と付き合うということ #
レザークラフトで使う革包丁は、買ってきたばかりの新品が一番切れるわけではない。 自分の手の大きさ、刃を入れる角度、作業台の高さに合わせて、砥石に当てて少しずつ刃先を研ぎ澄まし、手入れを重ねることで、ようやく「自分の体の一部」として馴染んでいく。
自宅サーバーというものも、まったく同じ手触りをしているのだと思う。
大手のクラウドサービスやレンタルサーバーを使えば、こうしたトラブルとは無縁でいられる。月額料金さえ払えば、99.99%の稼働率は向こうのエンジニアが保証してくれるし、真夜中に回線の不通に悩まされることもない。
けれど、誰かが用意したブラックボックスの上で暮らすことと、自分の手で組んだ小さな道具を手入れしながら暮らすことの間には、決定的な違いがある。
ベストエフォートの細い回線の上で、時々寝ぼけて立ち止まるトンネル。 そこに小さな自律神経(スクリプト)を一本通してやり、転んでも自分で起き上がれるように調教していく。 手間はかかるし、泥臭い。けれど、そうやって手を動かして問題をひとつずつ生活に馴染ませていく過程そのものが、私にとってはかけがえのない「デジタルな手仕事」なのだ。
嫁ちゃん
わたし
嫁ちゃん
わたし
足元を見ると、愛犬のそらがクッションに顎を乗せ、気持ちよさそうに大きめのあくびをひとつこぼしていた。 我が家のM1 Mac miniは、今日も部屋の片隅で、静かに呼吸を続けている。