docs: refresh trusted proxy auth guidance

This commit is contained in:
Peter Steinberger
2026-04-04 13:44:34 +01:00
parent 62babffc40
commit 7985cf5531

View File

@@ -53,8 +53,8 @@ Implications:
```json5
{
gateway: {
// Use loopback for same-host proxy setups; use lan/custom for remote proxy hosts
bind: "loopback",
// Trusted-proxy auth expects requests from a non-loopback trusted proxy source
bind: "lan",
// CRITICAL: Only add your proxy's IP(s) here
trustedProxies: ["10.0.0.1", "172.17.0.1"],
@@ -76,8 +76,12 @@ Implications:
}
```
If `gateway.bind` is `loopback`, include a loopback proxy address in
`gateway.trustedProxies` (`127.0.0.1`, `::1`, or an equivalent loopback CIDR).
Important runtime rule:
- Trusted-proxy auth rejects loopback-source requests (`127.0.0.1`, `::1`, loopback CIDRs).
- Same-host loopback reverse proxies do **not** satisfy trusted-proxy auth.
- For same-host loopback proxy setups, use token/password auth instead, or route through a non-loopback trusted proxy address that OpenClaw can verify.
- Non-loopback Control UI deployments still need explicit `gateway.controlUi.allowedOrigins`.
### Configuration Reference
@@ -179,7 +183,7 @@ Caddy with the `caddy-security` plugin can authenticate users and pass identity
{
gateway: {
bind: "lan",
trustedProxies: ["127.0.0.1"], // Caddy's IP (if on same host)
trustedProxies: ["10.0.0.1"], // Caddy/sidecar proxy IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
@@ -282,6 +286,7 @@ Behavior:
- When the header is present but empty, the request declares **no** operator scopes.
- When the header is absent, normal identity-bearing HTTP APIs fall back to the standard operator default scope set.
- Gateway-auth **plugin HTTP routes** are narrower by default: when `x-openclaw-scopes` is absent, their runtime scope falls back to `operator.write`.
- Browser-origin HTTP requests still have to pass `gateway.controlUi.allowedOrigins` (or deliberate Host-header fallback mode) even after trusted-proxy auth succeeds.
Practical rule:
@@ -295,8 +300,10 @@ Before enabling trusted-proxy auth, verify:
- [ ] **Proxy is the only path**: The Gateway port is firewalled from everything except your proxy
- [ ] **trustedProxies is minimal**: Only your actual proxy IPs, not entire subnets
- [ ] **No loopback proxy source**: trusted-proxy auth fails closed for loopback-source requests
- [ ] **Proxy strips headers**: Your proxy overwrites (not appends) `x-forwarded-*` headers from clients
- [ ] **TLS termination**: Your proxy handles TLS; users connect via HTTPS
- [ ] **allowedOrigins is explicit**: Non-loopback Control UI uses explicit `gateway.controlUi.allowedOrigins`
- [ ] **allowUsers is set** (recommended): Restrict to known users rather than allowing anyone authenticated
- [ ] **No mixed token config**: Do not set both `gateway.auth.token` and `gateway.auth.mode: "trusted-proxy"`
@@ -306,9 +313,11 @@ Before enabling trusted-proxy auth, verify:
The audit checks for:
- Base `gateway.trusted_proxy_auth` warning/critical reminder
- Missing `trustedProxies` configuration
- Missing `userHeader` configuration
- Empty `allowUsers` (allows any authenticated user)
- Wildcard or missing browser-origin policy on exposed Control UI surfaces
## Troubleshooting
@@ -320,6 +329,20 @@ The request didn't come from an IP in `gateway.trustedProxies`. Check:
- Is there a load balancer in front of your proxy?
- Use `docker inspect` or `kubectl get pods -o wide` to find actual IPs
### "trusted_proxy_loopback_source"
OpenClaw rejected a loopback-source trusted-proxy request.
Check:
- Is the proxy connecting from `127.0.0.1` / `::1`?
- Are you trying to use trusted-proxy auth with a same-host loopback reverse proxy?
Fix:
- Use token/password auth for same-host loopback proxy setups, or
- Route through a non-loopback trusted proxy address and keep that IP in `gateway.trustedProxies`.
### "trusted_proxy_user_missing"
The user header was empty or missing. Check:
@@ -339,6 +362,16 @@ A required header wasn't present. Check:
The user is authenticated but not in `allowUsers`. Either add them or remove the allowlist.
### "trusted_proxy_origin_not_allowed"
Trusted-proxy auth succeeded, but the browser `Origin` header did not pass Control UI origin checks.
Check:
- `gateway.controlUi.allowedOrigins` includes the exact browser origin
- You are not relying on wildcard origins unless you intentionally want allow-all behavior
- If you intentionally use Host-header fallback mode, `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` is set deliberately
### WebSocket Still Failing
Make sure your proxy: