Appearance
将 OpenClaw Gateway 的认证委托给身份感知反向代理(Pomerium、Caddy、nginx+OAuth)时使用 trusted-proxy 模式。关键操作:配置 gateway.trustedProxies 为代理实际 IP,设置 userHeader 接收用户身份,确保代理是访问 Gateway 的唯一路径。注意默认拒绝 loopback 源请求,如需同主机代理需显式启用 allowLoopback。启动后可用 openclaw security audit 审计配置安全性。
OpenClaw Trusted Proxy 认证配置:解决 WebSocket 1008 错误
安全敏感功能。 此模式将认证完全委托给你的反向代理。配置错误可能导致 Gateway 遭到未授权访问。启用前请仔细阅读。
什么场景用 Trusted Proxy
在以下情况使用 trusted-proxy 认证模式:
- 你在身份感知代理(Pomerium、Caddy + OAuth、nginx + oauth2-proxy、Traefik + forward auth)后面运行 OpenClaw
- 代理处理所有认证,并通过 Header 传递用户身份
- 你处于 Kubernetes 或容器环境,代理是访问 Gateway 的唯一路径
- 你遇到 WebSocket
1008 unauthorized错误——浏览器无法在 WS 载荷中传递 token
什么场景不用 Trusted Proxy
- 你的代理不认证用户(只做 TLS 终止或负载均衡)
- 存在绕过代理直接访问 Gateway 的路径(防火墙漏洞、内网直连)
- 你不确定代理是否正确剥离/覆盖转发的 Header
- 仅需个人单用户访问——建议使用 Tailscale Serve + 回环地址,配置更简单
工作原理
- 反向代理认证用户(OAuth、OIDC、SAML 等)
- 代理添加包含已认证用户身份的 Header(例如
x-forwarded-user: nick@example.com) - OpenClaw 验证请求来自受信任的代理 IP(在
gateway.trustedProxies中配置) - OpenClaw 从配置的 Header 中提取用户身份
- 一切检查通过,请求获得授权
控制台配对行为变化
当 gateway.auth.mode = "trusted-proxy" 且请求通过受信任代理检查后,Control UI WebSocket 会话可以不依赖设备配对身份直接连接。此时配对不再是主要访问关卡,反向代理的认证策略和 allowUsers 成为实际控制。务必通过 gateway.trustedProxies + 防火墙将 Gateway 入口锁定为仅受信任代理 IP。
怎么配置 Trusted Proxy 认证
json5
{
gateway: {
// Trusted-proxy 认证默认拒绝 loopback 源请求
bind: "lan",
// 关键:只添加你的代理 IP
trustedProxies: ["10.0.0.1", "172.17.0.1"],
auth: {
mode: "trusted-proxy",
trustedProxy: {
// 必填:包含已认证用户身份的 Header 名称
userHeader: "x-forwarded-user",
// 可选:必须存在的额外 Header(用于代理验证)
requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
// 可选:用户身份允许列表,空表示允许所有已认证用户
allowUsers: ["nick@example.com", "admin@company.org"],
// 可选:是否允许同主机 loopback 反向代理(默认 false)
allowLoopback: false,
},
},
},
}重要运行时规则
- Trusted-proxy 认证会拒绝来自 loopback 源的请求(
127.0.0.1、::1、loopback CIDR)。同主机 loopback 反向代理不满足条件,除非显式设置allowLoopback: true并包含 loopback 地址到trustedProxies。 - 启用
allowLoopback后,Gateway 信任本地进程发出的身份 Header,因此必须保证 Gateway 仍被防火墙屏蔽远程访问,且本地代理会覆盖客户端提供的身份 Header。 - 不经反向代理的内部 Gateway 客户端应使用
gateway.auth.password/OPENCLAW_GATEWAY_PASSWORD,而不是 trusted-proxy 身份 Header。 - 非 loopback 的 Control UI 部署仍需显式配置
gateway.controlUi.allowedOrigins。 - 注意:若请求到达 loopback 但携带了
Forwarded、X-Forwarded-*或X-Real-IP等 Header,这些证据会阻止本地直连的密码回退和设备身份门控。此时若allowLoopback已启用,trusted-proxy 仍可接受请求,但requiredHeaders和allowUsers继续生效。
配置参数参考
| 字段 | 必填 | 说明 |
|---|---|---|
gateway.trustedProxies | 是 | 受信任代理 IP 数组,来自其他 IP 的请求被拒绝 |
gateway.auth.mode | 是 | 必须为 "trusted-proxy" |
gateway.auth.trustedProxy.userHeader | 是 | 包含已认证用户身份的 Header 名称 |
gateway.auth.trustedProxy.requiredHeaders | 否 | 必须存在的额外 Header(代理验证) |
gateway.auth.trustedProxy.allowUsers | 否 | 用户身份允许列表,空表示允许所有已认证用户 |
gateway.auth.trustedProxy.allowLoopback | 否 | 允许同主机 loopback 反向代理(默认 false) |
仅当本地反向代理是预期信任边界时才启用
allowLoopback。任何能连接 Gateway 的本地进程都可能尝试发送身份 Header,所以需确保直接 Gateway 访问私有、且代理要求必须携带x-forwarded-proto等代理拥有的 Header。
TLS 终止和 HSTS 怎么配置
使用一个 TLS 终止点,并在该点应用 HSTS。
推荐:代理 TLS 终止
当反向代理处理 HTTPS(如 https://control.example.com)时,在代理侧设置 Strict-Transport-Security。证书和 HTTP 加固策略集中一处,OpenClaw 可保留在回环 HTTP。
text
Strict-Transport-Security: max-age=31536000; includeSubDomainsGateway 自身 TLS 终止
若 OpenClaw 直接提供 HTTPS,设置:
json5
{
gateway: {
tls: { enabled: true },
http: {
securityHeaders: {
strictTransportSecurity: "max-age=31536000; includeSubDomains",
},
},
},
}strictTransportSecurity 接受字符串值,或 false 显式禁用。
推出建议
- 先用短 max-age 验证(如
max-age=300) - 确认无误后改为长期值(如
max-age=31536000) - 仅当所有子域都已 HTTPS 时才加
includeSubDomains - 仅当整个域集符合 preload 要求时使用预加载
- 仅回环本地开发无需 HSTS
代理配置示例
Pomerium
Pomerium 通过 x-pomerium-claim-email 传递身份,JWT 在 x-pomerium-jwt-assertion。
json5
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"],
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-pomerium-claim-email",
requiredHeaders: ["x-pomerium-jwt-assertion"],
},
},
},
}Pomerium 路由配置:
yaml
routes:
- from: https://openclaw.example.com
to: http://openclaw-gateway:18789
policy:
- allow:
or:
- email:
is: nick@example.com
pass_identity_headers: trueCaddy + OAuth
使用 caddy-security 插件。
json5
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"],
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}
}
}nginx + oauth2-proxy
oauth2-proxy 使用 x-auth-request-email 传递身份。
json5
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"],
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-auth-request-email",
},
},
},
}nginx 配置:
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";
}Traefik + Forward Auth
json5
{
gateway: {
bind: "lan",
trustedProxies: ["172.17.0.1"], // Traefik 容器 IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}为什么启动报 "mixed_trusted_proxy_token" 错误
OpenClaw 拒绝同时启用 gateway.auth.token 或 OPENCLAW_GATEWAY_TOKEN 与 trusted-proxy 模式。混合配置会导致 loopback 请求走错认证路径。解决办法:
- 使用 trusted-proxy 模式时删除共享 token
- 如需 token 认证,将
gateway.auth.mode改为"token"
Loopback 请求仍会失败关闭,不会静默通过。内部调用者可改用 gateway.auth.password。
Operator 作用域 Header(x-openclaw-scopes)
Trusted-proxy 模式是携带身份的 HTTP 模式,调用方可选声明 operator 作用域:
x-openclaw-scopes: operator.readx-openclaw-scopes: operator.read,operator.writex-openclaw-scopes: operator.admin,operator.write
行为:
- Header 存在时,OpenClaw 遵守声明的 scope
- Header 存在但为空:声明无 operator 作用域
- Header 不存在:标准 API 回退到默认 operator 作用域;插件 HTTP 路由则回退到
operator.write - 浏览器 HTTP 请求仍需通过
gateway.controlUi.allowedOrigins检查
实用规则:想缩小权限时显式传递 x-openclaw-scopes。
安全检查清单
启用前确认:
- [ ] 代理是唯一路径:Gateway 端口只允许代理访问
- [ ] trustedProxies 最小化:只填实际代理 IP,不是整个子网
- [ ] Loopback 代理源已确认:除非显式启用
allowLoopback,否则 loopback 会被拒绝 - [ ] 代理剥离 Header:代理覆盖(而非追加)客户端的
x-forwarded-* - [ ] TLS 终止:代理处理 TLS,用户通过 HTTPS 连接
- [ ] allowedOrigins 显式:非 loopback Control UI 使用明确来源
- [ ] 设置 allowUsers(推荐):限制到已知用户
- [ ] 无混合 token 配置:不同时设置 token 和 trusted-proxy
- [ ] 本地密码回退私有:若配置了
gateway.auth.password,确保 Gateway 端口对远程防火墙
安全审计
openclaw security audit 会将 trusted-proxy 模式标记为严重等级(有意的提醒)。审计检查:
- 基础
gateway.trusted_proxy_auth提醒 - 缺少
trustedProxies - 缺少
userHeader allowUsers为空(允许任何已认证用户)allowLoopback启用- 暴露的 Control UI 入口缺 origin 策略
故障排查
"trusted_proxy_untrusted_source" 报错
请求 IP 不在 gateway.trustedProxies 中。检查:
- 代理 IP 是否正确?(Docker 容器 IP 会变化)
- 代理前是否有负载均衡?
- 使用
docker inspect或kubectl get pods -o wide查找实际 IP
"trusted_proxy_loopback_source" 怎么解决
同主机 loopback 反向代理被拒绝。解决方法:
- 改用 token/password 认证;或
- 通过非 loopback 受信任代理地址路由;或
- 若有意使用同主机代理,设置
allowLoopback: true并将 loopback 地址加入trustedProxies,同时确保代理覆盖身份 Header
"trusted_proxy_user_missing" 报错
用户 Header 为空或缺失。检查:
- 代理是否配置了传递身份 Header?
- Header 名称拼写是否正确(大小写不敏感但拼写重要)?
- 用户是否在代理端实际认证成功?
"trusted_proxy_missing_header_*" 怎么办
必需 Header 不存在。检查代理配置中是否添加了这些 Header,以及链路中是否有地方剥离。
"trusted_proxy_user_not_allowed"
用户已认证但不在 allowUsers 中。要么添加该用户,要么清空 allowUsers。
"trusted_proxy_origin_not_allowed"
Trusted-proxy 认证通过,但浏览器 Origin 未通过 Control UI 检查。检查:
gateway.controlUi.allowedOrigins是否包含确切浏览器 Origin- 是否意外使用了通配符
- 若使用 Host-header 回退模式,必须显式设置
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true
WebSocket 仍然失败
确保代理:
- 支持 WebSocket 升级(
Upgrade: websocket、Connection: upgrade) - 在 WebSocket 升级请求上也传递身份 Header(不只是 HTTP)
- 没有为 WebSocket 使用独立的认证路径
从 Token 认证迁移
- 配置代理认证用户并传递 Header
- 独立测试代理(curl 带上 Header)
- 更新 OpenClaw 配置为 trusted-proxy 模式
- 重启 Gateway
- 从 Control UI 测试 WebSocket
- 运行
openclaw security audit并审查结果
常见问题
为什么 WebSocket 1008 unauthorized 错误一直出现?
浏览器无法在 WebSocket 升级时传递 token,导致 token 认证失败。改用 trusted-proxy 模式后,代理通过身份 Header 认证用户,OpenClaw 验证代理 IP 并提取身份,即可解决此错误。
怎么配置 nginx + oauth2-proxy 实现 trusted-proxy?
在 OpenClaw 配置中设置 gateway.trustedProxies 为 nginx/oauth2-proxy 的 IP, userHeader 为 x-auth-request-email。nginx 配置中使用 auth_request 并设置 proxy_set_header X-Auth-Request-Email,同时开启 WebSocket 升级(proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade")。
启动报 "mixed_trusted_proxy_token" 怎么办?
说明同时设置了 gateway.auth.token 和 gateway.auth.mode: "trusted-proxy"。移除共享 token 或改用 mode: "token"。trusted-proxy 模式不支持 token 回退。