使用する場合
- OpenClaw を ID 認識プロキシ(Pomerium、Caddy + OAuth、nginx + oauth2-proxy、Traefik + forward auth)の背後で実行している。
- プロキシがすべての認証を処理し、ヘッダー経由でユーザー ID を渡す。
- Kubernetes またはコンテナ環境で、プロキシが Gateway への唯一の経路になっている。
- ブラウザーが WS ペイロードでトークンを渡せないため、WebSocket
1008 unauthorizedエラーが発生している。
使用しない場合
- プロキシがユーザーを認証していない(単なる TLS ターミネーターまたはロードバランサー)。
- プロキシを迂回して Gateway に到達できる経路がある(ファイアウォールの穴、内部ネットワークアクセス)。
- プロキシが転送ヘッダーを正しく削除または上書きしているか不明。
- 個人の単一ユーザーアクセスだけが必要(代わりに Tailscale Serve + loopback を検討)。
仕組み
Proxy adds an identity header
プロキシが、認証済みユーザー ID を含むヘッダーを追加します(例:
x-forwarded-user: nick@example.com)。Gateway verifies trusted source
OpenClaw は、リクエストが 信頼済みプロキシ IP(
gateway.trustedProxies)から来ており、Gateway 自身の loopback またはローカルインターフェースアドレスではないことを確認します。設定
設定リファレンス
信頼するプロキシ IP アドレス(または CIDR)の配列。他の IP からのリクエストは拒否されます。
"trusted-proxy" である必要があります。認証済みユーザー ID を含むヘッダー名。
リクエストを信頼するために存在している必要がある追加ヘッダー。
ユーザー ID の許可リスト。空の場合は、すべての認証済みユーザーを許可します。
同一ホストの loopback リバースプロキシを明示的にサポートします。
Control UI ペアリング動作
gateway.auth.mode = "trusted-proxy" が有効で、リクエストが trusted-proxy チェックを通過すると、Control UI WebSocket セッションはデバイスペアリング ID なしで接続できます。
スコープへの影響:
- デバイスなしの Control UI WebSocket セッションは接続できますが、デフォルトではオペレータースコープを受け取りません。OpenClaw は要求されたスコープリストを
[]にクリアするため、承認済みのペアリング済みデバイスまたはトークンに紐づいていないセッションは、権限を自己宣言できません。 - WebSocket 接続に成功した後にメソッドが
missing scopeで失敗する場合は、ブラウザーがデバイス ID を生成してペアリングを完了できるように HTTPS を使用してください。Control UI の安全でない HTTP を参照してください。 - 緊急時のみ:
gateway.controlUi.dangerouslyDisableDeviceAuth=trueは、デバイス ID がなくても要求されたスコープを保持します。これは重大なセキュリティ低下です。すばやく元に戻してください。Control UI の安全でない HTTP を参照してください。
x-openclaw-scopes を送信する場合、OpenClaw はセッションスコープを、要求されたスコープと宣言されたスコープの共通部分に制限します。このヘッダーはスコープを付与しません。セッションが保持できる内容を狭めるだけです。
影響:
- このモードでは、ペアリングは Control UI アクセスの主要なゲートではなくなります。
- リバースプロキシの認証ポリシーと
allowUsersが実効的なアクセス制御になります。 - Gateway の ingress は、信頼済みプロキシ IP のみにロックしてください(
gateway.trustedProxies+ ファイアウォール)。
gateway.controlUi.dangerouslyDisableDeviceAuth は、任意の client.mode: "backend" または CLI 風クライアントにスコープを付与しません。カスタム自動化では、デバイス ID/ペアリング、予約済みの直接ローカル client.id: "gateway-client" バックエンドヘルパーパス、または HTTP リクエスト/レスポンス面の方が適している場合は admin HTTP RPC Plugin を使用してください。
オペレータースコープヘッダー
trusted-proxy 認証は ID を伴う HTTP モードであるため、呼び出し元は HTTP API リクエストでx-openclaw-scopes を使ってオペレータースコープを任意で宣言できます。
注: WebSocket スコープは、Gateway プロトコルハンドシェイクとデバイス ID バインディングによって決まります。Control UI WebSocket アップグレードリクエストでは、x-openclaw-scopes はネゴシエートされたセッションスコープの上限にすぎず、付与ではありません。Control UI ペアリング動作 を参照してください。
例:
x-openclaw-scopes: operator.readx-openclaw-scopes: operator.read,operator.writex-openclaw-scopes: operator.admin,operator.write
- ヘッダーが存在する場合、OpenClaw は宣言されたスコープセットを尊重します。
- ヘッダーが存在するが空の場合、リクエストはオペレータースコープを 一切 宣言しません。
- ヘッダーが存在しない場合、通常の ID を伴う HTTP API は、標準のオペレーターデフォルトスコープセット(
operator.admin、operator.read、operator.write、operator.approvals、operator.pairing、operator.talk.secrets)にフォールバックします。 - Gateway 認証の Plugin HTTP ルート はデフォルトでより狭くなります。
x-openclaw-scopesが存在しない場合、ランタイムスコープはoperator.writeのみにフォールバックします。 - ブラウザー起点の HTTP リクエストは、trusted-proxy 認証が成功した後でも、
gateway.controlUi.allowedOrigins(または意図的な Host ヘッダーフォールバックモード)を通過する必要があります。
x-openclaw-scopes を明示的に送信してください。
TLS 終端と HSTS
TLS 終端ポイントを 1 つ使用し、そこで HSTS を適用してください。- Proxy TLS termination (recommended)
- Gateway TLS termination
リバースプロキシが
https://control.example.com の HTTPS を処理する場合、そのドメインに対してプロキシで Strict-Transport-Security を設定します。- インターネット向けデプロイに適しています。
- 証明書と HTTP 強化ポリシーを 1 か所に保てます。
- OpenClaw はプロキシの背後で loopback HTTP のままにできます。
ロールアウトガイダンス
- トラフィックを検証している間は、まず短い max age(例:
max-age=300)から始めます。 - 十分な確信が得られた後でのみ、長期間の値(例:
max-age=31536000)へ増やします。 - すべてのサブドメインが HTTPS 対応済みの場合にのみ、
includeSubDomainsを追加します。 - ドメインセット全体について preload 要件を意図的に満たす場合にのみ、preload を使用します。
- loopback のみのローカル開発では、HSTS の恩恵はありません。
プロキシ設定例
Pomerium
Pomerium
Pomerium は Pomerium 設定スニペット:
x-pomerium-claim-email(または他の claim ヘッダー)で ID を渡し、x-pomerium-jwt-assertion で JWT を渡します。Caddy with OAuth
Caddy with OAuth
caddy-security Plugin を使用した Caddy は、ユーザーを認証し、ID ヘッダーを渡すことができます。nginx + oauth2-proxy
nginx + oauth2-proxy
oauth2-proxy はユーザーを認証し、nginx 設定スニペット:
x-auth-request-email で ID を渡します。forward auth を使う Traefik
forward auth を使う Traefik
混在トークン設定
共有トークンも設定されている場合(gateway.auth.token または OPENCLAW_GATEWAY_TOKEN)、Gateway の起動は trusted-proxy 認証を拒否します。この 2 つは相互排他です。共有トークンを許可すると、このモードが強制することを意図しているプロキシ検証済み ID とはまったく別の経路で、同一ホストの呼び出し元が認証できてしまうためです。
起動が gateway auth mode is trusted-proxy, but a shared token is also configured のようなエラーで失敗する場合:
- trusted-proxy モードを使う場合は共有トークンを削除する、または
- トークンベース認証を意図している場合は
gateway.auth.modeを"token"に切り替えます。
gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD で認証できます。trusted-proxy モードでは、トークンのフォールバックは意図的に未対応のままです。
セキュリティチェックリスト
trusted-proxy 認証を有効にする前に、次を確認してください。- プロキシが唯一の経路である: Gateway ポートは、プロキシ以外のすべてからファイアウォールで遮断されている。
- trustedProxies は最小限である: サブネット全体ではなく、実際のプロキシ IP のみ。
- ループバックプロキシ送信元は意図的である:
gateway.auth.trustedProxy.allowLoopbackが同一ホストプロキシ用に明示的に有効化されていない限り、trusted-proxy 認証はループバック送信元リクエストを fail closed する。 - プロキシがヘッダーを除去する: プロキシはクライアントからの
x-forwarded-*ヘッダーを追加ではなく上書きする。 - TLS 終端: プロキシが TLS を処理し、ユーザーは HTTPS で接続する。
- allowedOrigins が明示的である: 非ループバックの Control UI は明示的な
gateway.controlUi.allowedOriginsを使う。 - allowUsers が設定されている(推奨): 認証済みなら誰でも許可するのではなく、既知のユーザーに制限する。
- 混在トークン設定がない:
gateway.auth.tokenとgateway.auth.mode: "trusted-proxy"の両方を設定しない。 - ローカルパスワードフォールバックは非公開である: 内部の直接呼び出し元向けに
gateway.auth.passwordを設定する場合、非プロキシのリモートクライアントが直接到達できないように Gateway ポートをファイアウォールで遮断する。
セキュリティ監査
openclaw security audit は trusted-proxy 認証を critical 重大度の検出事項としてフラグします。これは意図的な動作です。セキュリティをプロキシ設定に委任していることを思い出させるためです。
監査では次を確認します。
- 基本の
gateway.trusted_proxy_auth警告/critical リマインダー。 trustedProxies設定の欠落。userHeader設定の欠落。- 空の
allowUsers(認証済みユーザーを誰でも許可)。 - 同一ホストプロキシ送信元に対する
allowLoopbackの有効化。
gateway.controlUi.allowedOrigins、および Host ヘッダー origin フォールバックです。
トラブルシューティング
trusted_proxy_untrusted_source
trusted_proxy_untrusted_source
リクエストは
gateway.trustedProxies 内の IP から送信されていません。次を確認してください。- プロキシ IP は正しいですか?(Docker コンテナ IP は変わることがあります。)
- プロキシの前段にロードバランサーがありますか?
- 実際の IP を見つけるには、
docker inspectまたはkubectl get pods -o wideを使ってください。
trusted_proxy_loopback_source
trusted_proxy_loopback_source
OpenClaw はループバック送信元の trusted-proxy リクエストを拒否しました。確認:
- プロキシは
127.0.0.1/::1から接続していますか? - 同一ホストのループバックリバースプロキシで trusted-proxy 認証を使おうとしていますか?
- プロキシを通らない内部の同一ホストクライアントには、トークン/パスワード認証を優先する、または
- 非ループバックの信頼済みプロキシアドレス経由でルーティングし、その IP を
gateway.trustedProxiesに保持する、または - 意図的な同一ホストリバースプロキシの場合は、
gateway.auth.trustedProxy.allowLoopback = trueを設定し、ループバックアドレスをgateway.trustedProxiesに保持し、プロキシが ID ヘッダーを除去または上書きすることを確認します。
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
リクエストの送信元 IP が、Gateway ホスト自身の非ループバックネットワークインターフェースアドレスの 1 つ(プロキシではない)に一致しました。これは tailnet や Docker ブリッジネットワーク上の偽装された同一ホストトラフィックに対するガードです。
..._check_failed はインターフェース検出自体でエラーが発生したことを意味するため、OpenClaw は fail closed します。確認:- Gateway ホスト自身のプロセスが、プロキシを迂回して ID ヘッダーを直接送信していますか?
- プロキシは Gateway と同じネットワーク名前空間で実行され、ローカルインターフェースとしても表示される IP を持っていますか?
allowLoopback を使ってください。trusted_proxy_user_missing
trusted_proxy_user_missing
ユーザーヘッダーが空、または欠落しています。次を確認してください。
- プロキシは ID ヘッダーを渡すように設定されていますか?
- ヘッダー名は正しいですか?(大文字小文字は区別されませんが、綴りは重要です)
- ユーザーは実際にプロキシで認証されていますか?
trusted_proxy_missing_header_*
trusted_proxy_missing_header_*
必須ヘッダーが存在しませんでした。次を確認してください。
- それらの特定ヘッダーに対するプロキシ設定。
- チェーン内のどこかでヘッダーが除去されていないか。
trusted_proxy_user_not_allowed
trusted_proxy_user_not_allowed
ユーザーは認証済みですが、
allowUsers に含まれていません。ユーザーを追加するか、許可リストを削除してください。trusted_proxy_no_proxies_configured / trusted_proxy_config_missing
trusted_proxy_no_proxies_configured / trusted_proxy_config_missing
gateway.auth.mode は "trusted-proxy" ですが、gateway.trustedProxies が空であるか、gateway.auth.trustedProxy 自体が欠落しています。両方が設定されるまで、すべてのリクエストが拒否されます。trusted_proxy_origin_not_allowed
trusted_proxy_origin_not_allowed
Trusted-proxy 認証は成功しましたが、ブラウザーの
Origin ヘッダーが Control UI の origin チェックを通過しませんでした。確認:gateway.controlUi.allowedOriginsに正確なブラウザー origin が含まれている。- 意図的に全許可の動作を求めていない限り、ワイルドカード origin に依存していない。
- 意図的に Host ヘッダーフォールバックモードを使う場合、
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=trueが意図して設定されている。
接続は成功するが、メソッドがスコープ欠落を報告する
接続は成功するが、メソッドがスコープ欠落を報告する
WebSocket は接続しますが、
chat.history、sessions.list、または
models.list が missing scope: operator.read で失敗します。よくある原因:- デバイスなしの Control UI セッション: trusted-proxy 認証はデバイス ID なしで WebSocket 接続を許可できますが、OpenClaw は設計上、デバイスなしセッションのスコープをクリアします。
- カスタムバックエンドクライアント:
gateway.controlUi.dangerouslyDisableDeviceAuthは Control UI スコープであり、任意のバックエンドまたは CLI 形式の WebSocket クライアントにスコープを付与しません。 - 過度に狭い
x-openclaw-scopes: プロキシが Control UI WebSocket アップグレードリクエストにこのヘッダーを注入する場合、セッションスコープはその集合に制限されます。空のヘッダー値はスコープなしになります。
- Control UI では、ブラウザーがデバイス ID を生成してペアリングを完了できるように HTTPS を使ってください。
- カスタム自動化では、デバイス ID/ペアリング、予約済みの直接ローカル
gateway-clientバックエンドヘルパー経路、または admin HTTP RPC を使ってください。 gateway.controlUi.dangerouslyDisableDeviceAuth: trueは、一時的な Control UI の緊急回避経路としてのみ使ってください。
WebSocket がまだ失敗する
WebSocket がまだ失敗する
プロキシが次を満たしていることを確認してください。
- WebSocket アップグレードをサポートしている(
Upgrade: websocket、Connection: upgrade)。 - WebSocket アップグレードリクエストで ID ヘッダーを渡している(HTTP だけではない)。
- WebSocket 接続用の別個の認証経路を持っていない。
トークン認証からの移行
関連
- 設定 — 設定リファレンス
- オペレータースコープ — ロール、スコープ、承認チェック
- リモートアクセス — その他のリモートアクセスパターン
- セキュリティ — 完全なセキュリティガイド
- Tailscale — tailnet 専用アクセスのより簡単な代替手段