使用時機
- 你在具身分感知能力的代理後方執行 OpenClaw(Pomerium、Caddy + OAuth、nginx + oauth2-proxy、Traefik + forward auth)。
- 你的代理處理所有驗證,並透過標頭傳遞使用者身分。
- 你位於 Kubernetes 或容器環境中,且代理是通往閘道的唯一路徑。
- 你遇到 WebSocket
1008 unauthorized錯誤,因為瀏覽器無法在 WS 承載中傳遞權杖。
不應使用的時機
- 你的代理不會驗證使用者(只是 TLS 終止器或負載平衡器)。
- 有任何可繞過代理抵達閘道的路徑(防火牆漏洞、內部網路存取)。
- 你不確定代理是否正確移除/覆寫轉送標頭。
- 你只需要個人單一使用者存取(請改考慮 Tailscale Serve + loopback)。
運作方式
設定
設定參考
要信任的代理 IP 位址(或 CIDR)陣列。來自其他 IP 的請求會被拒絕。
必須是
"trusted-proxy"。包含已驗證使用者身分的標頭名稱。
請求要被信任時必須存在的額外標頭。
使用者身分允許清單。空值表示允許所有已驗證使用者。
對同主機 loopback 反向代理的明確啟用支援。
Control UI 配對行為
當gateway.auth.mode = "trusted-proxy" 啟用且請求通過 trusted-proxy 檢查時,Control UI WebSocket 工作階段可在沒有裝置配對身分的情況下連線。
範圍影響:
- 無裝置的 Control UI WebSocket 工作階段可以連線,但預設不會收到任何操作員範圍。OpenClaw 會將要求的範圍清單清空為
[],因此未繫結到已核准配對裝置/權杖的工作階段無法自行宣告權限。 - 如果 WebSocket 成功連線後方法因
missing scope失敗,請使用 HTTPS,讓瀏覽器可以產生裝置身分並完成配對。請參閱 Control UI 不安全 HTTP。 - 只限緊急破窗:
gateway.controlUi.dangerouslyDisableDeviceAuth=true會在沒有裝置身分時仍保留要求的範圍。這是嚴重的安全性降級;請快速還原。請參閱 Control UI 不安全 HTTP。
x-openclaw-scopes,OpenClaw 會將工作階段範圍限制為要求範圍與宣告範圍的交集。此標頭不會授予範圍;它只會縮小工作階段可持有的範圍。
影響:
- 在此模式中,配對不再是 Control UI 存取的主要閘門。
- 你的反向代理驗證政策與
allowUsers會成為有效的存取控制。 - 保持閘道入口只鎖定受信任代理 IP(
gateway.trustedProxies+ 防火牆)。
gateway.controlUi.dangerouslyDisableDeviceAuth 不會將範圍授予任意 client.mode: "backend" 或形似命令列介面的用戶端。自訂自動化應使用裝置身分/配對、保留的 direct-local client.id: "gateway-client" 後端輔助路徑,或在 HTTP 請求/回應介面更適合時使用 admin HTTP RPC 外掛。
操作員範圍標頭
Trusted-proxy 驗證是一種承載身分的 HTTP 模式,因此呼叫端可選擇在 HTTP API 請求上以x-openclaw-scopes 宣告操作員範圍。
注意:WebSocket 範圍由閘道協定握手與裝置身分繫結決定。在 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 會採用宣告的範圍集合。
- 當標頭存在但為空時,請求會宣告沒有操作員範圍。
- 當標頭不存在時,標準承載身分的 HTTP API 會 fallback 到標準操作員預設範圍集合(
operator.admin、operator.read、operator.write、operator.approvals、operator.pairing、operator.talk.secrets)。 - 閘道驗證的外掛 HTTP 路由預設更窄:當
x-openclaw-scopes不存在時,其執行階段範圍只會 fallback 到operator.write。 - 即使 trusted-proxy 驗證成功,瀏覽器來源的 HTTP 請求仍必須通過
gateway.controlUi.allowedOrigins(或刻意使用的 Host 標頭 fallback 模式)。
x-openclaw-scopes。
TLS 終止與 HSTS
使用一個 TLS 終止點,並在該處套用 HSTS。- 代理 TLS 終止(建議)
- 閘道 TLS 終止
當你的反向代理為
https://control.example.com 處理 HTTPS 時,請在該網域的代理上設定 Strict-Transport-Security。- 適合面向網際網路的部署。
- 將憑證與 HTTP 強化政策保留在同一處。
- 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 標頭)中傳遞身分,並在 x-pomerium-jwt-assertion 中傳遞 JWT。搭配 OAuth 的 Caddy
搭配 OAuth 的 Caddy
搭配 Caddyfile 片段:
caddy-security 外掛的 Caddy 可以驗證使用者並傳遞身分標頭。nginx + oauth2-proxy
nginx + oauth2-proxy
oauth2-proxy 會驗證使用者,並在 nginx 設定片段:
x-auth-request-email 中傳遞身分。Traefik with forward auth
Traefik with forward auth
混合權杖設定
如果也設定了共享權杖(gateway.auth.token 或 OPENCLAW_GATEWAY_TOKEN),閘道啟動會拒絕 trusted-proxy 驗證。兩者互斥,因為共享權杖會讓同主機呼叫端透過完全不同於此模式要強制使用的代理驗證身分路徑來驗證。
如果啟動失敗並出現類似 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 驗證前,請確認:- 代理是唯一路徑:閘道連接埠已由防火牆封鎖,只有你的代理可以存取。
- trustedProxies 最小化:只包含實際代理 IP,不要包含整個子網路。
- local loopback 代理來源是有意設定:除非為同主機代理明確啟用
gateway.auth.trustedProxy.allowLoopback,否則 trusted-proxy 驗證會對 local loopback 來源請求以失敗關閉處理。 - 代理會移除標頭:你的代理會覆寫(而不是附加)來自用戶端的
x-forwarded-*標頭。 - TLS 終止:你的代理處理 TLS;使用者透過 HTTPS 連線。
- allowedOrigins 是明確的:非 local loopback 控制 UI 使用明確的
gateway.controlUi.allowedOrigins。 - 已設定 allowUsers(建議):限制為已知使用者,而不是允許任何已驗證者。
- 沒有混合權杖設定:不要同時設定
gateway.auth.token和gateway.auth.mode: "trusted-proxy"。 - 本機密碼後援是私有的:如果你為內部直接呼叫端設定
gateway.auth.password,請保持閘道連接埠受防火牆保護,讓非代理的遠端用戶端無法直接連上。
安全稽核
openclaw security audit 會將 trusted-proxy 驗證標記為 嚴重 層級發現。這是有意為之;它是在提醒你正在把安全性委派給你的代理設定。
稽核會檢查:
- 基本
gateway.trusted_proxy_auth警告/嚴重提醒。 - 缺少
trustedProxies設定。 - 缺少
userHeader設定。 - 空的
allowUsers(允許任何已驗證使用者)。 - 為同主機代理來源啟用了
allowLoopback。
gateway.controlUi.allowedOrigins,以及 Host 標頭來源後援。
疑難排解
trusted_proxy_untrusted_source
trusted_proxy_untrusted_source
請求不是來自
gateway.trustedProxies 中的 IP。請檢查:- 代理 IP 是否正確?(Docker 容器 IP 可能會變更。)
- 你的代理前面是否有負載平衡器?
- 使用
docker inspect或kubectl get pods -o wide找出實際 IP。
trusted_proxy_loopback_source
trusted_proxy_loopback_source
OpenClaw 拒絕了 local loopback 來源的 trusted-proxy 請求。請檢查:
- 代理是否從
127.0.0.1/::1連線? - 你是否嘗試搭配同主機 local loopback 反向代理使用 trusted-proxy 驗證?
- 對於未經由代理的內部同主機用戶端,優先使用權杖/密碼驗證,或
- 透過非 local loopback 的受信任代理位址路由,並將該 IP 保留在
gateway.trustedProxies中,或 - 對於有意設定的同主機反向代理,設定
gateway.auth.trustedProxy.allowLoopback = true,將 local loopback 位址保留在gateway.trustedProxies中,並確認代理會移除或覆寫身分標頭。
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
trusted_proxy_local_interface_source / trusted_proxy_local_interface_check_failed
請求來源 IP 符合閘道主機自身的其中一個非 local loopback 網路介面位址(不是代理),這是防止 tailnet 或 Docker bridge 網路上偽造同主機流量的保護機制。
..._check_failed 表示介面探索本身發生錯誤,因此 OpenClaw 會以失敗關閉處理。請檢查:- 閘道主機上的程序是否正在繞過代理,直接傳送身分標頭?
- 代理是否與閘道在相同網路命名空間中執行,且其 IP 也顯示為本機介面?
allowLoopback。trusted_proxy_user_missing
trusted_proxy_user_missing
使用者標頭為空或缺失。請檢查:
- 你的代理是否已設定為傳遞身分標頭?
- 標頭名稱是否正確?(不區分大小寫,但拼字很重要)
- 使用者是否真的已在代理完成驗證?
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 標頭未通過控制 UI 來源檢查。請檢查:gateway.controlUi.allowedOrigins包含確切的瀏覽器來源。- 除非你有意允許全部行為,否則不要依賴萬用字元來源。
- 如果你有意使用 Host 標頭後援模式,請確認已刻意設定
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true。
Connection succeeds but methods report missing scope
Connection succeeds but methods report missing scope
WebSocket 已連線,但
chat.history、sessions.list 或
models.list 失敗並顯示 missing scope: operator.read。常見原因:- 無裝置的控制 UI 工作階段:trusted-proxy 驗證可以在沒有裝置身分的情況下允許 WebSocket 連線,但 OpenClaw 依設計會清除無裝置工作階段的作用域。
- 自訂後端用戶端:
gateway.controlUi.dangerouslyDisableDeviceAuth的範圍限定於控制 UI,且不會授予任意後端或命令列介面形狀的 WebSocket 用戶端作用域。 - 過度狹窄的
x-openclaw-scopes:如果你的代理在控制 UI WebSocket 升級請求上注入此標頭,工作階段作用域會被限制為該集合。空的標頭值會導致沒有任何作用域。
- 對於控制 UI,使用 HTTPS,讓瀏覽器可以產生裝置身分並完成配對。
- 對於自訂自動化,使用裝置身分/配對、保留的直接本機
gateway-client後端輔助路徑,或 admin HTTP RPC。 - 只將
gateway.controlUi.dangerouslyDisableDeviceAuth: true作為暫時的控制 UI 緊急通道。
WebSocket still failing
WebSocket still failing
確認你的代理:
- 支援 WebSocket 升級(
Upgrade: websocket、Connection: upgrade)。 - 在 WebSocket 升級請求上傳遞身分標頭(不只是 HTTP)。
- 沒有為 WebSocket 連線使用不同的驗證路徑。