2026 OpenClaw 本番リバースプロキシと TLS:
Nginx/Caddy での WebSocket、サブパスと Gateway の 502/ハンドシェイク切り分け

約16分 · MACCOME

コンテナ内では正常に見えるのに、Nginx/Caddy の背後では 502、WebSocket ハンドシェイク失敗、無限リダイレクト? 本文はエッジのリバースプロキシ + TLS 終端 + WebSocket アップグレードに絞る。Docker ネットワーク切り分けと補完関係で、そちらはパケットの到達性、こちらはブラウザから Gateway までの HTTP/1.1 アップグレード経路とパスを扱う。6 つの典型落とし穴、トポロジと症状の対照表、コピペ用スニペット、6 ステップの本番 Runbook、オンコール向け指標が 3 つ。読後は Upgrade を直すべきか、上流 127.0.0.1:18789 に戻るべきか判断できる。

リバプロでよくある 6 つの誤解(curl が通っても 502 になる理由)

  1. proxy_pass だけで HTTP/1.1 と Upgrade がない:WebSocket 利用時にエッジで 400/502 になり、ログは Gateway 落ちに見える。
  2. サブパスの二重プレフィックス:プロキシが /openclaw を剥がしてもアプリがルート基準の絶対 URL を出し、静的資産と WS パスが分裂する。
  3. HTTP/2 リスナーと WS を混在させ ALPN を未検証:WS 専用サーバや明示的な HTTP/1.1 フォールバックが必要な組み合わせがあり、握手が断続的に失敗する。
  4. proxy_read_timeout が短すぎる:長い推論やチャネルバーストでエッジが静かに切断し、再接続ストームが上流を直撃する。
  5. 不完全な証明書チェーンをブラウザ警告だけで済ませる:自動化クライアントは厳しく、デスクトップ CLI は通るのに Web UI だけ失敗することがある。
  6. CDN のデフォルトキャッシュや短いアイドルタイムアウト:制御面 WebSocket が通常 GET のように扱われたり早期切断され、ランダム切断に見える。

次のトポロジ表で同一ホスト/別ホスト/サブドメイン/サブパスのトレードオフを整理し、その後ヘッダチェックと症状マトリクスへ進む。

トポロジ選択:同一ホスト、別ホスト、サブパス、サブドメインが切り分けに与える影響

同一ホストのリバプロ(Nginx/Caddy と Gateway 同居)は最短経路で、curl -v http://127.0.0.1:18789 で上流を検証できる。別ホストはホップが増え、セキュリティグループ、内部 DNS、TLS SNI を再確認する。サブドメインはパス剥がしや Cookie Path の衝突を避けやすい。サブパスは単一ブランドホスト向きだが、OpenClaw のベース URL とプロキシの両方でプレフィックスは一度だけ剥がし、開発者ツールで WS URL が期待する wss:// を指すか確認する。

変更依頼にはスクリーンショットを 2 枚添付する:最終的なアドレスバーと、Network タブの WebSocket 握手 Request URL。無いとレビューがモデルタイムアウトやチャネル OAuth に誤分類され、リリース時間を浪費する。企業 HTTPS プロキシがある場合、オフィスブラウザ(PAC 注入)とデータセンターのリバプロ(多くは直結)を分けて考える。症状の不一致は普通に起きる。

2026 年もエッジ HTTP/2 と上流 HTTP/1.1 WebSocket の組み合わせは一般的。どのホップでアップグレードが許可されるかを確認する。パケット取得なしに強制 H2 とカスタム WS 書き換えを同時に有効にしないこと。

トポロジ向く用途運用メリット典型の落とし穴
同一ホスト + ループバック上流単一 VPS / 常時稼働リモート Macローカル curl で切り分け、TLS とプロセスが同じログ0.0.0.0 バインドで露出が増える。FW で抑える
専用リバプロホスト多バックエンド、ブルーグリーン、WAF 前置エッジと計算プールを分離、証明書更新を集中化内部ルート、SNI、ヘルスチェック先のドリフト
サブドメインWS を本サイトから分離パス意味が明確、CDN ルールが書きやすい複数証明書、HSTS は別レビュー
サブパス単一ブランドエントリドメインユーザーが覚えやすいプレフィックス剥がし、リダイレクトループ、資産ルートのずれ

Nginx と Caddy:WebSocket に必要なヘッダとタイムアウト対照

どちらの実装でも、エッジは HTTP/1.1 へのアップグレード、Connection: upgradeUpgrade: websocket の透過または再構築、そしてモデル最遅分位より長い読み取りタイムアウトが必要。表はコードレビュー用チェックリスト。

見落としがちなのはプロキシバッファ。通常 API では proxy_buffering がスループットに効くが、ストリーミングや長寿命接続では遅延や切断感を招く。ストリーム型チャネルや SSE 的挙動がある場合はステージングで実負荷をかけてからデフォルトバッファを有効にする。

チェックNginx の要点Caddy の要点
プロトコル版proxy_http_version 1.1;reverse_proxy は既定で HTTP/1.1。明示 transport に注意
Upgrade チェーンUpgrade $http_upgrade; Connection "upgrade";多くは自動。カスタムは header_up
Host とクライアント IPproxy_set_header Host $host;X-Forwarded-*header_up Host {host}。プロキシホップの信頼
長寿命接続proxy_read_timeout / send_timeouttransport http { read_timeout ... }(版ごとの構文はドキュメント参照)
大きなボディclient_max_body_sizeボディ制限系ディレクティブ(Caddy ドキュメント参照)
nginx
# スニペット: ローカル Gateway へリバプロ(ポートは環境に合わせる。例 18789)
location / {
  proxy_pass http://127.0.0.1:18789;
  proxy_http_version 1.1;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_read_timeout 3600s;
  proxy_send_timeout 3600s;
}
Caddyfile
# スニペット: 自動 TLS + WebSocket 上流
openclaw.example.com {
    reverse_proxy 127.0.0.1:18789 {
        header_up Host {host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}
info

ヒント:設定変更後はまず上流側で curl -v -H "Connection: Upgrade" -H "Upgrade: websocket" http://127.0.0.1:18789/ により握手の意味を確認し、その後に公開 wss:// を試す。さもなくば TLS とプロキシの間で責任が往復する。

症状マトリクス:502、413、101 以外、リダイレクト、証明書

症状をエッジ・上流・アプリ設定にマッピングしてからコンテナを作り直す。表がコンテナネットワークを指すなら Docker ネットワーク切り分けへ。チャネルは繋がるが Slack/Telegram が沈黙なら チャネル接続トラブルシュートを参照。

本番だけ再現しステージングは正常なら、証明書チェーンの CA、CDN/WAF ルールの版、プロキシの map/if が User-Agent で分岐していないかを差分比較する。多くの 502 はエッジの誤検知で、OpenClaw の版とは無関係。

症状まず疑うもの検証
502 Bad Gateway上流未リッスン、FW、ソケット族の誤りリバプロから上流へ curl。error.log の upstream timed out / refused
413 Request Entity Too Largeエッジの client_max_body_size が小さい値を上げて reload。CDN/WAF 側の制限も同期
WS が 101 にならないUpgrade 欠落、パス書き換え、http→https リダイレクトが握手を壊すブラウザ Network で握手ステータス。location 順と return 301
リダイレクトループX-Forwarded-Proto なしで HTTPS 強制テストでエッジ HSTS を一時緩和。Forwarded ヘッダを補完
証明書警告/一部クライアントのみ失敗チェーン欠落、誤 SNI、IP 証明書の混在openssl s_client -servername でチェーン確認。NTP

6 ステップ Runbook:パイロットホスト名からオンコール可能な本番入口へ

  1. URL 方針を固定:公開 https:// ベース、サブパス有無、WS が HTTP と同じ host かを文書化。
  2. ローカルプローブ:リバプロホストからループバック上流へ直撃し、OpenClaw のプロセス/ポートがドキュメントと一致することを確認(例 18789)。
  3. 最小 Nginx/Caddy 断片:まずヘルスパスのみリバプロし、段階的にサイト全体へ。各段階でロールバック可能にする。
  4. 1 本の完全な WS セッションを取得:ブラウザと CLI の両方で検証し、request_id があればログを揃える。
  5. セキュリティを積む:IP 許可、レート制限、カスタム WAF。トークン方針は Docker 本番 Runbook と整合。
  6. 観測ベースライン:上流 P95、分あたり WS 再接続、証明書残日数を記録しアラート閾値に落とす。
  7. ロールバック演習:メンテ窓で「リバプロ設定だけ戻し、イメージは戻さない」練習をし、実行コマンド列を文書化する。

Grafana とオンコール手順に書くべき硬い指標が 3 つ

  1. 上流 RTT P95:プロキシワーカーから 127.0.0.1:18789 または内部 VIP まで。公遅延と切り離し、遅さがエッジか Gateway かを判断しやすい。
  2. WebSocket の異常クローズ率:分単位で集計。急増はタイムアウト、リリース、モデル側 429 と相関しやすい。プロバイダルーティング記事と照合。
  3. 証明書の残存期間:残 14 日未満でチケット。Let's Encrypt と商用 CA の更新失敗はステージングで先に演習。

集中ログがあるなら、リバプロ access の 5xx 率Gateway アプリのエラー率を二軸で並べる。片方だけが跳ねたとき責務境界が明確になり、ポストモーテムがデータで語れる。

ノートパソコンだけで Gateway を動かすと本番入口と長期自動化に耐えにくい理由

ノート上のリバプロ実験はスニペット検証には速いが、スリープ、VPN 切替、不安定な家庭用アップリンクは TLS と更新を手作業にする。502 の SLO を契約に落とせない。リバプロ + 常時 Gateway を 24/7 の専用ホスト(例:レンタルの Apple Silicon クラウド Mac や管理下 VPS)に置けば、レート制限、証明書、ログ保持が標準変更になる。入口が安定して初めて OpenClaw と CI、署名パイプラインの連携が監査と引き継ぎに耐える。

自前リバプロスタックは OpenSSL、Nginx、OS の CVE 追従も必要。OpenClaw を CI、署名、マルチチャネル Bot に長期結びつけるチームにとって、予測可能な専有算力と明確なリージョン/契約期間は家庭用出口の実験より総コストで有利なことが多い。MACCOME のクラウド Mac は複数リージョンと明確なレンタル帯を提供し、TLS 終端の背後にあるクリーンな常駐機として適する。まず 3 プラットフォームのインストールと選定でディレクトリと権限境界を固め、Mac mini レンタル料金と地域ページ——シンガポール東京ソウル香港バージニアシリコンバレー——で実行層を契約可能な環境へ移し、エッジのリバプロはポリシーと観測だけを担う。

接続、セッション、チャネル系の論点は ヘルプセンターでキーワード検索し、視覚的な切り分けにはリモートデスクトップや SSH/VNC の記事と組み合わせる。

よくある質問

502 のとき、プロキシと Docker のどちらを先に見る?

リバプロホストからループバック上流を curl。不通なら Docker ネットワーク切り分けへ。プラン比較は Mac mini レンタル料金

サブパスとサブドメイン、どう選ぶ?

サブドメインは剥がし問題を避けやすい。サブパスは両側のベース URL を一致させる。インストールは 3 プラットフォーム インストールガイドで版を揃える。

CDN 越しに WS が落ちる

キャッシュを切る、アイドルタイムアウトを延ばす、制御面用サブドメインで CDN をバイパスする。チャネル側は Slack/Discord/Telegram 切り分けを参照。

ログとチケットはどこへ?

エンタープライズ変更は ヘルプセンターのチケットへ。本番チャットに Nginx 設定の半分を流さない。