Gateway
احراز هویت پروکسی مورد اعتماد
زمان استفاده
از حالت احراز هویت trusted-proxy زمانی استفاده کنید که:
- OpenClaw را پشت یک پراکسی آگاه از هویت اجرا میکنید (Pomerium، Caddy + OAuth، nginx + oauth2-proxy، Traefik + forward auth).
- پراکسی شما تمام احراز هویت را انجام میدهد و هویت کاربر را از طریق headerها ارسال میکند.
- در یک محیط Kubernetes یا container هستید که پراکسی تنها مسیر دسترسی به Gateway است.
- با خطاهای WebSocket
1008 unauthorizedروبهرو میشوید چون مرورگرها نمیتوانند tokenها را در payloadهای WS ارسال کنند.
زمان عدم استفاده
- اگر پراکسی شما کاربران را احراز هویت نمیکند (فقط یک TLS terminator یا load balancer است).
- اگر هر مسیری به Gateway وجود دارد که پراکسی را دور میزند (حفرههای firewall، دسترسی شبکه داخلی).
- اگر مطمئن نیستید پراکسی شما headerهای forwarded را درست حذف/بازنویسی میکند.
- اگر فقط به دسترسی شخصی تککاربره نیاز دارید (برای راهاندازی سادهتر، Tailscale Serve + loopback را در نظر بگیرید).
نحوه کار
Proxy authenticates the user
پراکسی معکوس شما کاربران را احراز هویت میکند (OAuth، OIDC، SAML و غیره).
Proxy adds an identity header
پراکسی یک header با هویت کاربر احرازشده اضافه میکند (مثلاً x-forwarded-user: nick@example.com).
Gateway verifies trusted source
OpenClaw بررسی میکند که درخواست از یک IP پراکسی مورد اعتماد آمده باشد (در gateway.trustedProxies پیکربندی شده است).
Gateway extracts identity
OpenClaw هویت کاربر را از header پیکربندیشده استخراج میکند.
Authorize
اگر همه چیز درست باشد، درخواست مجاز میشود.
رفتار pairing در Control UI
وقتی gateway.auth.mode = "trusted-proxy" فعال است و درخواست بررسیهای trusted-proxy را با موفقیت میگذراند، نشستهای WebSocket در Control UI میتوانند بدون هویت pairing دستگاه وصل شوند.
پیامدهای scope:
- نشستهای WebSocket در Control UI بدون دستگاه وصل میشوند، اما بهطور پیشفرض هیچ scope اپراتوری دریافت نمیکنند. OpenClaw فهرست scope درخواستی را به
[]پاک میکند تا نشستی که به دستگاه/token pairing و تأییدشده متصل نیست، نتواند خودش مجوزها را اعلام کند. - اگر methodها پس از اتصال موفق WebSocket با
missing scopeشکست خوردند، از HTTPS استفاده کنید تا مرورگر بتواند هویت دستگاه را ایجاد کند و pairing را کامل کند. Control UI insecure HTTP را ببینید. - فقط برای شرایط اضطراری:
gateway.controlUi.dangerouslyDisableDeviceAuth=trueحتی بدون هویت دستگاه، scopeهای درخواستی را حفظ میکند. این یک کاهش امنیتی شدید است؛ سریعاً آن را برگردانید. Control UI insecure HTTP را ببینید.
محدودسازی scope توسط پراکسی معکوس:
- اگر پراکسی شما در درخواست upgrade WebSocket مربوط به Control UI،
x-openclaw-scopesرا ارسال کند، OpenClaw scopeهای نشست را به اشتراک scopeهای درخواستی و scopeهای اعلامشده محدود میکند. این header scope اعطا نمیکند؛ فقط آنچه نشست میتواند نگه دارد را محدودتر میکند.
پیامدها:
- در این حالت، pairing دیگر gate اصلی برای دسترسی به Control UI نیست.
- سیاست احراز هویت پراکسی معکوس شما و
allowUsersبه کنترل دسترسی مؤثر تبدیل میشوند. - ورودی Gateway را فقط به IPهای پراکسی مورد اعتماد قفل نگه دارید (
gateway.trustedProxies+ firewall).
کلاینتهای سفارشی WebSocket نشست Control UI نیستند. gateway.controlUi.dangerouslyDisableDeviceAuth به کلاینتهای دلخواه client.mode: "backend" یا کلاینتهای شبیه CLI، scope اعطا نمیکند. automation سفارشی باید از هویت دستگاه/pairing، مسیر helper backend رزروشده direct-local با client.id: "gateway-client"، یا admin HTTP RPC Plugin استفاده کند، وقتی سطح درخواست/پاسخ HTTP گزینه مناسبتری است.
پیکربندی
{ gateway: { // Trusted-proxy auth expects requests from a non-loopback trusted proxy source 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, }, }, },}مرجع پیکربندی
gateway.trustedProxiesstring[]requiredآرایهای از آدرسهای IP پراکسی که باید به آنها اعتماد شود. درخواستها از IPهای دیگر رد میشوند.
gateway.auth.modestringrequiredباید "trusted-proxy" باشد.
gateway.auth.trustedProxy.userHeaderstringrequiredنام header که هویت کاربر احرازشده را در خود دارد.
gateway.auth.trustedProxy.requiredHeadersstring[]headerهای اضافی که باید برای مورد اعتماد بودن درخواست حاضر باشند.
gateway.auth.trustedProxy.allowUsersstring[]allowlist هویتهای کاربری. خالی بودن یعنی همه کاربران احرازشده مجاز هستند.
gateway.auth.trustedProxy.allowLoopbackbooleanپشتیبانی opt-in برای پراکسیهای معکوس loopback روی همان host. پیشفرض false است.
پایاندهی TLS و HSTS
از یک نقطه پایاندهی TLS استفاده کنید و HSTS را همانجا اعمال کنید.
Proxy TLS termination (recommended)
وقتی پراکسی معکوس شما HTTPS را برای https://control.example.com مدیریت میکند، Strict-Transport-Security را در پراکسی برای آن دامنه تنظیم کنید.
- برای استقرارهای رو به اینترنت مناسب است.
- سیاست certificate + سختسازی HTTP را در یک نقطه نگه میدارد.
- OpenClaw میتواند پشت پراکسی روی HTTP loopback باقی بماند.
نمونه مقدار header:
Strict-Transport-Security: max-age=31536000; includeSubDomainsGateway TLS termination
اگر خود OpenClaw مستقیماً HTTPS را ارائه میکند (بدون پراکسی پایاندهنده TLS)، تنظیم کنید:
{ gateway: { tls: { enabled: true }, http: { securityHeaders: { strictTransportSecurity: "max-age=31536000; includeSubDomains", }, }, },}strictTransportSecurity یک مقدار string برای header میپذیرد، یا false برای غیرفعالسازی صریح.
راهنمای rollout
- ابتدا با max age کوتاه شروع کنید (برای مثال
max-age=300) در حالی که ترافیک را اعتبارسنجی میکنید. - فقط پس از بالا رفتن اطمینان، آن را به مقادیر بلندمدت افزایش دهید (برای مثال
max-age=31536000). - فقط اگر هر subdomain آماده HTTPS است،
includeSubDomainsرا اضافه کنید. - فقط اگر عمداً الزامات preload را برای مجموعه کامل دامنههای خود برآورده میکنید، از preload استفاده کنید.
- توسعه محلی فقط روی loopback از HSTS سودی نمیبرد.
نمونههای راهاندازی پراکسی
Pomerium
Pomerium هویت را در x-pomerium-claim-email (یا headerهای claim دیگر) و یک JWT را در x-pomerium-jwt-assertion ارسال میکند.
{ 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: trueCaddy with OAuth
Caddy با Plugin caddy-security میتواند کاربران را احراز هویت کند و headerهای هویت را ارسال کند.
{ 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} }}nginx + oauth2-proxy
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";}Traefik with forward auth
{ gateway: { bind: "lan", trustedProxies: ["172.17.0.1"], // Traefik container IP auth: { mode: "trusted-proxy", trustedProxy: { userHeader: "x-forwarded-user", }, }, },}پیکربندی token مختلط
OpenClaw پیکربندیهای مبهمی را که در آنها هم gateway.auth.token (یا OPENCLAW_GATEWAY_TOKEN) و هم حالت trusted-proxy همزمان فعال هستند رد میکند. پیکربندیهای token مختلط میتوانند باعث شوند درخواستهای loopback بیصدا در مسیر احراز هویت اشتباه احراز هویت شوند.
اگر هنگام startup خطای mixed_trusted_proxy_token دیدید:
- هنگام استفاده از حالت trusted-proxy، token مشترک را حذف کنید، یا
- اگر قصد احراز هویت مبتنی بر token دارید،
gateway.auth.modeرا به"token"تغییر دهید.
هدرهای هویت پراکسی معتمد local loopback همچنان در حالت fail closed شکست میخورند: فراخوانندههای همان میزبان بیصدا بهعنوان کاربران پراکسی احراز هویت نمیشوند. فراخوانندههای داخلی OpenClaw که پراکسی را دور میزنند میتوانند در عوض با gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD احراز هویت کنند. fallback توکن در حالت پراکسی معتمد عمداً پشتیبانی نمیشود.
هدر دامنههای اپراتور
احراز هویت پراکسی معتمد یک حالت HTTP حامل هویت است، بنابراین فراخوانندهها میتوانند بهصورت اختیاری دامنههای اپراتور را با x-openclaw-scopes در درخواستهای HTTP API اعلام کنند.
نکته: دامنههای WebSocket توسط handshake پروتکل Gateway و اتصال هویت دستگاه تعیین میشوند. در درخواستهای ارتقای WebSocket برای Control UI، x-openclaw-scopes فقط سقفی برای دامنههای نشست مذاکرهشده است، نه یک اعطا. برای رفتار دامنه WebSocket با پراکسی معتمد، رفتار جفتسازی Control UI را ببینید.
نمونهها:
x-openclaw-scopes: operator.readx-openclaw-scopes: operator.read,operator.writex-openclaw-scopes: operator.admin,operator.write
رفتار:
- وقتی هدر وجود دارد، OpenClaw مجموعه دامنه اعلامشده را رعایت میکند.
- وقتی هدر وجود دارد اما خالی است، درخواست هیچ دامنه اپراتوری اعلام نمیکند.
- وقتی هدر وجود ندارد، APIهای HTTP عادیِ حامل هویت به مجموعه دامنه پیشفرض استاندارد اپراتور fallback میکنند.
- مسیرهای HTTP Plugin با احراز هویت Gateway بهصورت پیشفرض محدودترند: وقتی
x-openclaw-scopesوجود ندارد، دامنه زمان اجرای آنها بهoperator.writefallback میکند. - درخواستهای HTTP با مبدأ مرورگر همچنان باید از
gateway.controlUi.allowedOrigins(یا حالت fallback عمدی Host-header) عبور کنند، حتی پس از موفقیت احراز هویت پراکسی معتمد. - برای نشستهای WebSocket در Control UI، وقتی
x-openclaw-scopesدر درخواست ارتقا وجود داشته باشد، سقف دامنه است. مقدار خالی به هیچ دامنهای منجر نمیشود.
قاعده عملی: وقتی میخواهید درخواست پراکسی معتمد از پیشفرضها محدودتر باشد، یا وقتی یک مسیر Plugin با احراز هویت gateway به چیزی قویتر از دامنه نوشتن نیاز دارد، x-openclaw-scopes را صریحاً ارسال کنید.
چکلیست امنیت
پیش از فعالکردن احراز هویت پراکسی معتمد، بررسی کنید:
- [ ] پراکسی تنها مسیر است: پورت Gateway از همهچیز بهجز پراکسی شما پشت فایروال است.
- [ ] trustedProxies حداقلی است: فقط IPهای واقعی پراکسی شما، نه کل زیرشبکهها.
- [ ] مبدأ پراکسی local loopback عمدی است: احراز هویت پراکسی معتمد برای درخواستهای با مبدأ local loopback در حالت fail closed شکست میخورد، مگر اینکه
gateway.auth.trustedProxy.allowLoopbackصریحاً برای پراکسی همان میزبان فعال شده باشد. - [ ] پراکسی هدرها را حذف میکند: پراکسی شما هدرهای
x-forwarded-*از کلاینتها را بازنویسی میکند (نه اینکه به آنها اضافه کند). - [ ] پایاندهی TLS: پراکسی شما TLS را مدیریت میکند؛ کاربران از طریق HTTPS وصل میشوند.
- [ ] allowedOrigins صریح است: Control UI غیر local loopback از
gateway.controlUi.allowedOriginsصریح استفاده میکند. - [ ] allowUsers تنظیم شده است (توصیهشده): بهجای اجازهدادن به هر کاربر احراز هویتشده، دسترسی را به کاربران شناختهشده محدود کنید.
- [ ] پیکربندی توکن ترکیبی وجود ندارد: همزمان
gateway.auth.tokenوgateway.auth.mode: "trusted-proxy"را تنظیم نکنید. - [ ] fallback رمز عبور محلی خصوصی است: اگر
gateway.auth.passwordرا برای فراخوانندههای مستقیم داخلی پیکربندی میکنید، پورت Gateway را پشت فایروال نگه دارید تا کلاینتهای راهدور غیرپراکسی نتوانند مستقیماً به آن برسند.
ممیزی امنیت
openclaw security audit احراز هویت پراکسی معتمد را با یافتهای با شدت critical علامتگذاری میکند. این عمدی است — یادآوری میکند که امنیت را به راهاندازی پراکسی خود واگذار کردهاید.
ممیزی این موارد را بررسی میکند:
- هشدار/یادآوری critical پایه
gateway.trusted_proxy_auth - نبود پیکربندی
trustedProxies - نبود پیکربندی
userHeader allowUsersخالی (اجازه به هر کاربر احراز هویتشده)- فعال بودن
allowLoopbackبرای مبدأهای پراکسی همان میزبان - سیاست مبدأ مرورگر wildcard یا مفقود در سطحهای درمعرضدسترسی Control UI
عیبیابی
trusted_proxy_untrusted_source
درخواست از IP موجود در gateway.trustedProxies نیامده است. بررسی کنید:
- آیا IP پراکسی درست است؟ (IPهای کانتینر Docker میتوانند تغییر کنند.)
- آیا جلوی پراکسی شما load balancer وجود دارد؟
- برای یافتن IPهای واقعی از
docker inspectیاkubectl get pods -o wideاستفاده کنید.
trusted_proxy_loopback_source
OpenClaw یک درخواست پراکسی معتمد با مبدأ local loopback را رد کرد.
بررسی کنید:
- آیا پراکسی از
127.0.0.1/::1وصل میشود؟ - آیا میخواهید احراز هویت پراکسی معتمد را با یک reverse proxy local loopback روی همان میزبان استفاده کنید؟
رفع مشکل:
- برای کلاینتهای داخلی همان میزبان که از پراکسی عبور نمیکنند، احراز هویت توکن/رمز عبور را ترجیح دهید، یا
- از طریق یک آدرس پراکسی معتمد غیر local loopback مسیریابی کنید و آن IP را در
gateway.trustedProxiesنگه دارید، یا - برای یک reverse proxy عمدی روی همان میزبان،
gateway.auth.trustedProxy.allowLoopback = trueرا تنظیم کنید، آدرس local loopback را درgateway.trustedProxiesنگه دارید، و مطمئن شوید پراکسی هدرهای هویت را حذف یا بازنویسی میکند.
trusted_proxy_user_missing
هدر کاربر خالی بود یا وجود نداشت. بررسی کنید:
- آیا پراکسی شما برای عبوردادن هدرهای هویت پیکربندی شده است؟
- آیا نام هدر درست است؟ (به حروف بزرگ و کوچک حساس نیست، اما املا مهم است)
- آیا کاربر واقعاً در پراکسی احراز هویت شده است؟
trusted_proxy_missing_header_*
یک هدر لازم وجود نداشت. بررسی کنید:
- پیکربندی پراکسی شما برای آن هدرهای مشخص.
- آیا هدرها در جایی از زنجیره حذف میشوند یا نه.
trusted_proxy_user_not_allowed
کاربر احراز هویت شده اما در allowUsers نیست. یا او را اضافه کنید یا allowlist را حذف کنید.
trusted_proxy_origin_not_allowed
احراز هویت پراکسی معتمد موفق شد، اما هدر Origin مرورگر از بررسیهای مبدأ Control UI عبور نکرد.
بررسی کنید:
gateway.controlUi.allowedOriginsشامل مبدأ دقیق مرورگر باشد.- مگر اینکه عمداً رفتار allow-all میخواهید، به مبدأهای wildcard تکیه نکنید.
- اگر عمداً از حالت fallback برای Host-header استفاده میکنید،
gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=trueبهصورت عمدی تنظیم شده باشد.
Connection succeeds but methods report missing scope
WebSocket وصل میشود، اما chat.history، sessions.list، یا
models.list با missing scope: operator.read شکست میخورد.
علتهای رایج:
- نشست Control UI بدون دستگاه: احراز هویت پراکسی معتمد میتواند اتصال WebSocket را بدون هویت دستگاه بپذیرد، اما OpenClaw طبق طراحی دامنهها را در نشستهای بدون دستگاه پاک میکند.
- کلاینت backend سفارشی:
gateway.controlUi.dangerouslyDisableDeviceAuthمحدود به Control UI است و به کلاینتهای WebSocket دلخواه backend یا شبیه CLI دامنه اعطا نمیکند. x-openclaw-scopesبیشازحد محدود: اگر پراکسی شما این هدر را در درخواست ارتقای WebSocket برای Control UI تزریق کند، دامنههای نشست به آن مجموعه محدود میشوند. مقدار هدر خالی به هیچ دامنهای منجر نمیشود.
رفع مشکل:
- برای Control UI، از HTTPS استفاده کنید تا مرورگر بتواند هویت دستگاه تولید کند و جفتسازی را کامل کند.
- برای خودکارسازی سفارشی، از هویت/جفتسازی دستگاه، مسیر helper backend رزروشده direct-local با نام
gateway-client، یا admin HTTP RPC استفاده کنید. - از
gateway.controlUi.dangerouslyDisableDeviceAuth: trueفقط بهعنوان مسیر موقت break-glass برای Control UI استفاده کنید.
WebSocket still failing
مطمئن شوید پراکسی شما:
- از ارتقاهای WebSocket پشتیبانی میکند (
Upgrade: websocket،Connection: upgrade). - هدرهای هویت را در درخواستهای ارتقای WebSocket عبور میدهد (نه فقط HTTP).
- مسیر احراز هویت جداگانهای برای اتصالهای WebSocket ندارد.
مهاجرت از احراز هویت توکن
اگر از احراز هویت توکن به پراکسی معتمد منتقل میشوید:
Configure the proxy
پراکسی خود را برای احراز هویت کاربران و عبوردادن هدرها پیکربندی کنید.
Test the proxy independently
راهاندازی پراکسی را بهصورت مستقل آزمایش کنید (curl با هدرها).
Update OpenClaw config
پیکربندی OpenClaw را با احراز هویت پراکسی معتمد بهروزرسانی کنید.
Restart the Gateway
Gateway را راهاندازی مجدد کنید.
Test WebSocket
اتصالهای WebSocket را از Control UI آزمایش کنید.
Audit
openclaw security audit را اجرا کنید و یافتهها را مرور کنید.
مرتبط
- پیکربندی — مرجع پیکربندی
- دسترسی راهدور — الگوهای دیگر دسترسی راهدور
- امنیت — راهنمای کامل امنیت
- Tailscale — جایگزین سادهتر برای دسترسی فقط tailnet