跳轉到主要內容
安全性敏感功能。 此模式會將驗證完全委派給你的反向代理。設定錯誤可能會讓你的閘道暴露於未授權存取。啟用前請仔細閱讀本頁。

使用時機

  • 你在具身分感知能力的代理後方執行 OpenClaw(Pomerium、Caddy + OAuth、nginx + oauth2-proxy、Traefik + forward auth)。
  • 你的代理處理所有驗證,並透過標頭傳遞使用者身分。
  • 你位於 Kubernetes 或容器環境中,且代理是通往閘道的唯一路徑。
  • 你遇到 WebSocket 1008 unauthorized 錯誤,因為瀏覽器無法在 WS 承載中傳遞權杖。

不應使用的時機

  • 你的代理不會驗證使用者(只是 TLS 終止器或負載平衡器)。
  • 有任何可繞過代理抵達閘道的路徑(防火牆漏洞、內部網路存取)。
  • 你不確定代理是否正確移除/覆寫轉送標頭。
  • 你只需要個人單一使用者存取(請改考慮 Tailscale Serve + loopback)。

運作方式

1

代理驗證使用者

你的反向代理會驗證使用者(OAuth、OIDC、SAML 等)。
2

代理加入身分標頭

代理會加入含有已驗證使用者身分的標頭(例如 x-forwarded-user: nick@example.com)。
3

閘道驗證受信任來源

OpenClaw 會檢查請求是否來自受信任代理 IPgateway.trustedProxies),且不是閘道本身的 loopback 或本機介面位址。
4

閘道擷取身分

OpenClaw 會讀取必要標頭,接著從設定的標頭讀取使用者身分。
5

授權

如果所有檢查都通過,且使用者通過 allowUsers(設定時),請求就會被授權。

設定

{
  gateway: {
    // Trusted-proxy auth expects the proxy's source IP to be non-loopback by default
    bind: "lan",

    // CRITICAL: Only add your proxy's IP(s) here
    trustedProxies: ["10.0.0.1", "172.17.0.1"],

    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        // Header containing authenticated user identity (required)
        userHeader: "x-forwarded-user",

        // Optional: headers that MUST be present (proxy verification)
        requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],

        // Optional: restrict to specific users (empty = allow all)
        allowUsers: ["nick@example.com", "admin@company.org"],

        // Optional: allow a same-host loopback proxy after explicit opt-in
        allowLoopback: false,
      },
    },
  },
}
執行階段規則,依評估順序
  1. 請求的來源 IP 必須符合 gateway.trustedProxies(支援 CIDR),否則會被拒絕(trusted_proxy_untrusted_source)。
  2. loopback 來源請求(127.0.0.1::1)會被拒絕,除非 gateway.auth.trustedProxy.allowLoopback = true,且該 loopback 位址也在 trustedProxies 中(trusted_proxy_loopback_source)。這項檢查會在標頭檢查前執行,因此即使必要標頭也缺失,loopback 來源仍會以此方式失敗。
  3. 符合閘道主機自身某個本機網路介面位址的非 loopback 來源,會作為防偽裝保護而被拒絕(trusted_proxy_local_interface_source)。如果介面探索本身失敗,請求也會被拒絕(trusted_proxy_local_interface_check_failed)。
  4. requiredHeadersuserHeader 必須存在且非空白。
  5. allowUsers 若非空,必須包含擷取出的使用者。
轉送標頭證據會覆寫 local-direct fallback 的 loopback 本地性。 如果請求抵達 loopback,但帶有 Forwarded、任何 X-Forwarded-*X-Real-IP 標頭,該證據會使其不符合 local-direct 密碼 fallback 和裝置身分閘控的資格,即使它仍會因 loopback 而無法通過 trusted-proxy 驗證。allowLoopback 會以與反向代理相同的程度信任閘道主機上的本機程序。只有在閘道仍受防火牆保護、無法被遠端直接存取,且本機代理會移除或覆寫用戶端提供的身分標頭時,才啟用它。不經過反向代理的內部閘道用戶端應使用 gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD,而不是 trusted-proxy 身分標頭。非 loopback 的 Control UI 部署仍需要明確的 gateway.controlUi.allowedOrigins

設定參考

gateway.trustedProxies
string[]
必填
要信任的代理 IP 位址(或 CIDR)陣列。來自其他 IP 的請求會被拒絕。
gateway.auth.mode
string
必填
必須是 "trusted-proxy"
gateway.auth.trustedProxy.userHeader
string
必填
包含已驗證使用者身分的標頭名稱。
gateway.auth.trustedProxy.requiredHeaders
string[]
請求要被信任時必須存在的額外標頭。
gateway.auth.trustedProxy.allowUsers
string[]
使用者身分允許清單。空值表示允許所有已驗證使用者。
gateway.auth.trustedProxy.allowLoopback
boolean
預設值:"false"
對同主機 loopback 反向代理的明確啟用支援。
只有當本機反向代理是預期的信任邊界時,才啟用 allowLoopback。任何可連線到閘道的本機程序都能嘗試傳送代理身分標頭,因此請將直接閘道存取限制為主機私有,並要求代理擁有的標頭,例如 x-forwarded-proto,或在你的代理支援時使用簽署的斷言標頭。

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
反向代理範圍上限:如果你的代理在 Control UI WebSocket 升級請求上傳送 x-openclaw-scopes,OpenClaw 會將工作階段範圍限制為要求範圍與宣告範圍的交集。此標頭不會授予範圍;它只會縮小工作階段可持有的範圍。 影響:
  • 在此模式中,配對不再是 Control UI 存取的主要閘門。
  • 你的反向代理驗證政策與 allowUsers 會成為有效的存取控制。
  • 保持閘道入口只鎖定受信任代理 IP(gateway.trustedProxies + 防火牆)。
自訂 WebSocket 用戶端不是 Control UI 工作階段。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.read
  • x-openclaw-scopes: operator.read,operator.write
  • x-openclaw-scopes: operator.admin,operator.write
行為:
  • 當標頭存在時,OpenClaw 會採用宣告的範圍集合。
  • 當標頭存在但為空時,請求會宣告沒有操作員範圍。
  • 當標頭不存在時,標準承載身分的 HTTP API 會 fallback 到標準操作員預設範圍集合(operator.adminoperator.readoperator.writeoperator.approvalsoperator.pairingoperator.talk.secrets)。
  • 閘道驗證的外掛 HTTP 路由預設更窄:當 x-openclaw-scopes 不存在時,其執行階段範圍只會 fallback 到 operator.write
  • 即使 trusted-proxy 驗證成功,瀏覽器來源的 HTTP 請求仍必須通過 gateway.controlUi.allowedOrigins(或刻意使用的 Host 標頭 fallback 模式)。
實務規則:當你想讓 trusted-proxy 請求比預設更窄,或當 gateway-auth 外掛路由需要比寫入範圍更強的權限時,請明確傳送 x-openclaw-scopes

TLS 終止與 HSTS

使用一個 TLS 終止點,並在該處套用 HSTS。
當你的反向代理為 https://control.example.com 處理 HTTPS 時,請在該網域的代理上設定 Strict-Transport-Security
  • 適合面向網際網路的部署。
  • 將憑證與 HTTP 強化政策保留在同一處。
  • OpenClaw 可在代理後方保持使用 loopback HTTP。
標頭值範例:
Strict-Transport-Security: max-age=31536000; includeSubDomains

推出指引

  • 驗證流量時,先從較短的 max age 開始(例如 max-age=300)。
  • 只有在信心很高後,才增加到長效值(例如 max-age=31536000)。
  • 只有在每個子網域都已準備好 HTTPS 時,才加入 includeSubDomains
  • 只有在你刻意滿足完整網域集合的 preload 要求時,才使用 preload。
  • 只使用 loopback 的本機開發無法受益於 HSTS。

代理設定範例

Pomerium 會在 x-pomerium-claim-email(或其他 claim 標頭)中傳遞身分,並在 x-pomerium-jwt-assertion 中傳遞 JWT。
{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // Pomerium's IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-pomerium-claim-email",
        requiredHeaders: ["x-pomerium-jwt-assertion"],
      },
    },
  },
}
Pomerium 設定片段:
routes:
  - from: https://openclaw.example.com
    to: http://openclaw-gateway:18789
    policy:
      - allow:
          or:
            - email:
                is: nick@example.com
    pass_identity_headers: true
搭配 caddy-security 外掛的 Caddy 可以驗證使用者並傳遞身分標頭。
{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // Caddy/sidecar proxy IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}
Caddyfile 片段:
openclaw.example.com {
    authenticate with oauth2_provider
    authorize with policy1

    reverse_proxy openclaw:18789 {
        header_up X-Forwarded-User {http.auth.user.email}
    }
}
oauth2-proxy 會驗證使用者,並在 x-auth-request-email 中傳遞身分。
{
  gateway: {
    bind: "lan",
    trustedProxies: ["10.0.0.1"], // nginx/oauth2-proxy IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-auth-request-email",
      },
    },
  },
}
nginx 設定片段:
location / {
    auth_request /oauth2/auth;
    auth_request_set $user $upstream_http_x_auth_request_email;

    proxy_pass http://openclaw:18789;
    proxy_set_header X-Auth-Request-Email $user;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}
{
  gateway: {
    bind: "lan",
    trustedProxies: ["172.17.0.1"], // Traefik container IP
    auth: {
      mode: "trusted-proxy",
      trustedProxy: {
        userHeader: "x-forwarded-user",
      },
    },
  },
}

混合權杖設定

如果也設定了共享權杖(gateway.auth.tokenOPENCLAW_GATEWAY_TOKEN),閘道啟動會拒絕 trusted-proxy 驗證。兩者互斥,因為共享權杖會讓同主機呼叫端透過完全不同於此模式要強制使用的代理驗證身分路徑來驗證。 如果啟動失敗並出現類似 gateway auth mode is trusted-proxy, but a shared token is also configured 的錯誤:
  • 使用 trusted-proxy 模式時移除共享權杖,或
  • 如果你打算使用權杖式驗證,請將 gateway.auth.mode 切換為 "token"
local loopback trusted-proxy 身分標頭仍會以失敗關閉處理:同主機呼叫端不會被靜默驗證為代理使用者。繞過代理的 OpenClaw 內部呼叫端可以改用 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.tokengateway.auth.mode: "trusted-proxy"
  • 本機密碼後援是私有的:如果你為內部直接呼叫端設定 gateway.auth.password,請保持閘道連接埠受防火牆保護,讓非代理的遠端用戶端無法直接連上。

安全稽核

openclaw security audit 會將 trusted-proxy 驗證標記為 嚴重 層級發現。這是有意為之;它是在提醒你正在把安全性委派給你的代理設定。 稽核會檢查:
  • 基本 gateway.trusted_proxy_auth 警告/嚴重提醒。
  • 缺少 trustedProxies 設定。
  • 缺少 userHeader 設定。
  • 空的 allowUsers(允許任何已驗證使用者)。
  • 為同主機代理來源啟用了 allowLoopback
每當控制 UI 對外暴露時,也會套用個別的非 trusted-proxy 專屬發現:萬用字元或缺少 gateway.controlUi.allowedOrigins,以及 Host 標頭來源後援。

疑難排解

請求不是來自 gateway.trustedProxies 中的 IP。請檢查:
  • 代理 IP 是否正確?(Docker 容器 IP 可能會變更。)
  • 你的代理前面是否有負載平衡器?
  • 使用 docker inspectkubectl get pods -o wide 找出實際 IP。
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 中,並確認代理會移除或覆寫身分標頭。
請求來源 IP 符合閘道主機自身的其中一個非 local loopback 網路介面位址(不是代理),這是防止 tailnet 或 Docker bridge 網路上偽造同主機流量的保護機制。..._check_failed 表示介面探索本身發生錯誤,因此 OpenClaw 會以失敗關閉處理。請檢查:
  • 閘道主機上的程序是否正在繞過代理,直接傳送身分標頭?
  • 代理是否與閘道在相同網路命名空間中執行,且其 IP 也顯示為本機介面?
修正方式:透過不會同時綁定在閘道主機本機上的位址路由代理流量,或只在真正的同主機代理設定中使用 allowLoopback
使用者標頭為空或缺失。請檢查:
  • 你的代理是否已設定為傳遞身分標頭?
  • 標頭名稱是否正確?(不區分大小寫,但拼字很重要)
  • 使用者是否真的已在代理完成驗證?
缺少必要標頭。請檢查:
  • 你的代理對這些特定標頭的設定。
  • 標頭是否在鏈路中的某處被移除。
使用者已驗證,但不在 allowUsers 中。請加入該使用者或移除允許清單。
gateway.auth.mode"trusted-proxy",但 gateway.trustedProxies 為空,或 gateway.auth.trustedProxy 本身缺失。在兩者都設定之前,所有請求都會被拒絕。
Trusted-proxy 驗證成功,但瀏覽器 Origin 標頭未通過控制 UI 來源檢查。請檢查:
  • gateway.controlUi.allowedOrigins 包含確切的瀏覽器來源。
  • 除非你有意允許全部行為,否則不要依賴萬用字元來源。
  • 如果你有意使用 Host 標頭後援模式,請確認已刻意設定 gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true
WebSocket 已連線,但 chat.historysessions.listmodels.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 升級(Upgrade: websocketConnection: upgrade)。
  • 在 WebSocket 升級請求上傳遞身分標頭(不只是 HTTP)。
  • 沒有為 WebSocket 連線使用不同的驗證路徑。

從權杖驗證遷移

1

Configure the proxy

設定你的代理以驗證使用者並傳遞標頭。
2

Test the proxy independently

獨立測試代理設定(帶標頭的 curl)。
3

Update OpenClaw config

更新 OpenClaw 設定以使用 trusted-proxy 驗證。
4

Restart the Gateway

重新啟動閘道。
5

Test WebSocket

從控制 UI 測試 WebSocket 連線。
6

Audit

執行 openclaw security audit 並檢視發現。

相關