Trusted proxy auth
기준일: 2026-07-26
공식 기준: Trusted proxy auth
Trusted proxy auth 문서는 OpenClaw 공식 문서(gateway/trusted-proxy-auth)를 한국어로 정리한 가이드입니다. Delegate gateway authentication to a trusted reverse proxy (Pomerium, Caddy, nginx + OAuth) 명령·설정 키·코드 예시는 공식 문서를 그대로 보존하며, 해석과 절차 안내는 한국어로 제공합니다. 최종 동작은 설치된 CLI 버전과 공식 원문을 확인하세요.
핵심 요약
Delegate gateway authentication to a trusted reverse proxy (Pomerium, Caddy, nginx + OAuth)
한국어 가이드 범위: gateway/trusted-proxy-auth 경로의 설정·명령·제약·예시를 학습용으로 재구성합니다.
문서 구성
공식 문서의 주요 섹션은 다음과 같습니다.
- When to use
- When NOT to use
- 동작 방식
- 구성
- Configuration reference
- Automatic device approval
- Control UI pairing behavior
- Operator scopes header
- TLS termination and HSTS
- Rollout guidance
- Proxy setup examples
- Mixed token configuration
- Security checklist
- Security audit
- 트러블슈팅
- Migration from token auth
- 관련 문서
상세 내용
본문
Security-sensitive feature. This mode delegates authentication entirely to your reverse proxy. Misconfiguration can expose your Gateway to unauthorized access. Read this page carefully before enabling.
When to use
주요 항목:
- You run OpenClaw behind an identity-aware proxy (Pomerium, Caddy + OAuth, nginx + oauth2-proxy, Traefik + forward auth).
- Your proxy handles all authentication and passes user identity via headers.
- You're in a Kubernetes or container environment where the proxy is the only path to the Gateway.
- You're hitting WebSocket
1008 unauthorizederrors because browsers can't pass tokens in WS payloads.
When NOT to use
주요 항목:
- Your proxy doesn't authenticate users (just a TLS terminator or load balancer).
- There's any path to the Gateway that bypasses the proxy (firewall holes, internal network access).
- You're unsure whether your proxy correctly strips/overwrites forwarded headers.
- You only need personal single-user access (consider Tailscale Serve + loopback instead).
동작 방식
Your reverse proxy authenticates users (OAuth, OIDC, SAML, etc.).
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
구성
- The request's source IP must match
gateway.trustedProxies(CIDR-aware), or it is rejected (trusted_proxy_untrusted_source). 2. Loopback-source requests (127.0.0.1,::1) are rejected unlessgateway.auth.trustedProxy.allowLoopback = trueand the loopback address is also intrustedProxies(trusted_proxy_loopback_source). This check runs before header checks, so a loopback source fails this way even if required headers are also missing. 3. Non-loopback sources that match one of the Gateway host's own local network interface addresses are rejected as a spoofing guard (trusted_proxy_local_interface_source). If interface discovery itself fails, the request is rejected too (trusted_proxy_local_interface_check_failed). 4.requiredHeadersanduserHeadermust be present and non-blank. 5.allowUsers, if non-empty, must include the extracted user.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
{
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,
// Optional: let authenticated proxy users enroll new browser devices
deviceAutoApprove: {
enabled: false,
scopes: ["operator.read", "operator.write", "operator.approvals"],
},
},
},
},
}
Configuration reference
Array of proxy IP addresses (or CIDRs) to trust. Requests from other IPs are rejected.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
Automatic device approval
Trusted-proxy auth can optionally use the proxy identity as the approval boundary for new browser devices:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
{
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
allowUsers: ["operator@example.com"],
deviceAutoApprove: {
enabled: true,
scopes: ["operator.read", "operator.write", "operator.approvals"],
},
},
},
},
}
Control UI pairing behavior
When gateway.auth.mode = "trusted-proxy" is active and the request passes trusted-proxy checks, Control UI WebSocket sessions can connect without device pairing identity.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Device-less Control UI WebSocket sessions connect but receive no operator scopes by default. OpenClaw clears the requested scope list to
[]so a session not bound to an approved paired device/token cannot self-declare permissions. - If methods fail with
missing scopeafter a successful WebSocket connect, use HTTPS so the browser can generate device identity and complete pairing. See Control UI insecure HTTP. - Older configs that still contain the retired
- Pairing is no longer the primary gate for device-less Control UI access. When
deviceAutoApprove.enabledis true, the proxy identity also becomes the approval gate for new browser device enrollment. - Your reverse proxy auth policy and
allowUsersbecome the effective access control. - Keep gateway ingress locked to trusted proxy IPs only (
gateway.trustedProxies+ firewall).
Operator scopes header
Trusted-proxy auth is an identity-bearing HTTP mode, so callers may optionally declare operator scopes with x-openclaw-scopes on HTTP API requests.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
x-openclaw-scopes: operator.readx-openclaw-scopes: operator.read,operator.writex-openclaw-scopes: operator.admin,operator.write- When the header is present, OpenClaw honors the declared scope set.
- 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 (
operator.admin,operator.read,operator.write,operator.approvals,operator.pairing,operator.talk.secrets). - Gateway-auth plugin HTTP routes are narrower by default: when
x-openclaw-scopesis absent, their runtime scope falls back tooperator.writeonly. - Browser-origin HTTP requests still have to pass
gateway.controlUi.allowedOrigins(or deliberate Host-header fallback mode) even after trusted-proxy auth succeeds.
TLS termination and HSTS
Use one TLS termination point and apply HSTS there.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Good fit for internet-facing deployments.
- Keeps certificate + HTTP hardening policy in one place.
- OpenClaw can stay on loopback HTTP behind the proxy.
Strict-Transport-Security: max-age=31536000; includeSubDomains
{
gateway: {
tls: { enabled: true },
http: {
securityHeaders: {
strictTransportSecurity: "max-age=31536000; includeSubDomains",
},
},
},
}
Rollout guidance
주요 항목:
- Start with a short max age first (for example
max-age=300) while validating traffic. - Increase to long-lived values (for example
max-age=31536000) only after confidence is high. - Add
includeSubDomainsonly if every subdomain is HTTPS-ready. - Use preload only if you intentionally meet preload requirements for your full domain set.
- Loopback-only local development does not benefit from HSTS.
Proxy setup examples
Pomerium passes identity in x-pomerium-claim-email (or other claim headers) and a JWT in x-pomerium-jwt-assertion.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- from: https://openclaw.example.com
- allow:
- email:
{
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"],
},
},
},
}
routes:
- from: https://openclaw.example.com
to: http://openclaw-gateway:18789
policy:
- allow:
or:
- email:
is: nick@example.com
pass_identity_headers: true
{
gateway: {
bind: "lan",
trustedProxies: ["10.0.0.1"], // Caddy/sidecar proxy IP
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
},
},
},
}
openclaw.example.com {
authenticate with oauth2_provider
authorize with policy1
reverse_proxy openclaw:18789 {
header_up X-Forwarded-User {http.auth.user.email}
}
}
Mixed token configuration
Gateway startup rejects trusted-proxy auth if a shared token is also configured (gateway.auth.token or OPENCLAW_GATEWAY_TOKEN). The two are mutually exclusive because a shared token would let same-host callers authenticate on a completely different path than the proxy-verified identity this mode is meant to enforce.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Remove the shared token when using trusted-proxy mode, or
- Switch
gateway.auth.modeto"token"if you intend token-based auth.
Security checklist
Before enabling trusted-proxy auth, verify:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- 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.
- Loopback proxy source is deliberate: trusted-proxy auth fails closed for loopback-source requests unless
gateway.auth.trustedProxy.allowLoopbackis explicitly enabled for a same-host proxy. - 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.tokenandgateway.auth.mode: "trusted-proxy". - Local password fallback is private: If you configure
gateway.auth.passwordfor internal direct callers, keep the Gateway port firewalled so non-proxy remote clients cannot reach it directly. - Device auto-approval is deliberate: If
deviceAutoApprove.enabledis true, treat reverse-proxy account security as the device-enrollment boundary and keep the granted scope list non-admin and minimal.
Security audit
openclaw security audit flags trusted-proxy auth with a critical severity finding. This is intentional; it's a reminder that you're delegating security to your proxy setup.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Base
gateway.trusted_proxy_authwarning/critical reminder. - Missing
trustedProxiesconfiguration. - Missing
userHeaderconfiguration. - Empty
allowUsers(allows any authenticated user). - Enabled
allowLoopbackfor same-host proxy sources. - Enabled browser device auto-approval (delegates new device pairing to the proxy identity).
트러블슈팅
The request didn't come from an IP in gateway.trustedProxies. Check:
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
주요 항목:
- Is the proxy IP correct? (Docker container IPs can change.)
- Is there a load balancer in front of your proxy?
- Use
docker inspectorkubectl get pods -o wideto find actual IPs. - 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?
- Prefer token/password auth for internal same-host clients that do not go through the proxy, or
- Route through a non-loopback trusted proxy address and keep that IP in
gateway.trustedProxies, or - For a deliberate same-host reverse proxy, set
gateway.auth.trustedProxy.allowLoopback = true, keep the loopback address ingateway.trustedProxies, and make sure the proxy strips or overwrites identity headers. - Is a process on the Gateway host itself sending identity headers directly, bypassing the proxy?
- Does the proxy run in the same network namespace as the Gateway, with an IP that also shows up as a local interface?
- Is your proxy configured to pass identity headers?
- Is the header name correct? (case-insensitive, but spelling matters)
- Is the user actually authenticated at the proxy?
- Your proxy configuration for those specific headers.
- Whether headers are being stripped somewhere in the chain.
gateway.controlUi.allowedOriginsincludes 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=trueis set deliberately. - Device-less Control UI session: trusted-proxy auth can admit the WebSocket connection without device identity, but OpenClaw clears scopes on device-less sessions by design.
- Custom backend client: the retired Control UI upgrade input never grants access to arbitrary backend or CLI-shaped WebSocket clients.
- Overly narrow
x-openclaw-scopes: if your proxy injects this header on the Control UI WebSocket upgrade request, the session scopes are capped to that set. An empty header value yields no scopes. - For Control UI, use HTTPS so the browser can generate device identity and complete pairing.
- For custom automation, use device identity/pairing, the reserved direct-local
gateway-clientbackend helper path, or admin HTTP RPC. - Do not add the retired
gateway.controlUi.dangerouslyDisableDeviceAuthkey to current config. Older installs use the one-time self-pairing migration automatically. - Supports WebSocket upgrades (
Upgrade: websocket,Connection: upgrade).
Migration from token auth
Configure your proxy to authenticate users and pass headers.
위 내용은 공식 문서의 해당 섹션 요지입니다. 세부 플래그·기본값은 원문과
--help를 확인하세요.
관련 문서
주요 항목:
- Configuration — config reference
- Operator scopes — roles, scopes, and approval checks
- Remote access — other remote access patterns
- Security — full security guide
- Tailscale — simpler alternative for tailnet-only access
실습 체크리스트
- 공식 문서와 로컬 버전을 대조합니다:
https://docs.openclaw.ai/gateway/trusted-proxy-auth - 관련 CLI는
openclaw --help및 하위 명령--help로 옵션을 확인합니다. - 설정 변경 시
openclaw config/openclaw doctor로 유효성을 검사합니다. - Gateway·채널·플러그인 변경 후에는 필요 시 Gateway를 재시작합니다.
자주 쓰는 명령·설정 예시
{
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,
// Optional: let authenticated proxy users enroll new browser devices
deviceAutoApprove: {
enabled: false,
scopes: ["operator.read", "operator.write", "operator.approvals"],
},
},
},
},
}
{
gateway: {
auth: {
mode: "trusted-proxy",
trustedProxy: {
userHeader: "x-forwarded-user",
allowUsers: ["operator@example.com"],
deviceAutoApprove: {
enabled: true,
scopes: ["operator.read", "operator.write", "operator.approvals"],
},
},
},
},
}
Strict-Transport-Security: max-age=31536000; includeSubDomains
{
gateway: {
tls: { enabled: true },
http: {
securityHeaders: {
strictTransportSecurity: "max-age=31536000; includeSubDomains",
},
},
},
}
{
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"],
},
},
},
}
routes:
- from: https://openclaw.example.com
to: http://openclaw-gateway:18789
policy:
- allow:
or:
- email:
is: nick@example.com
pass_identity_headers: true
관련 링크
이 가이드는 공식 문서를 한국어 학습용으로 재구성한 것입니다. 옵션 기본값·플래그 이름은 설치 버전에 따라 달라질 수 있습니다.