מדריך קלוד קוד בעברית

תיעוד 113

פריסה ותפעול של Claude apps gateway

רשמו את השער אצל ספק הזהויות, בנו את הקונטיינר, פרסו ב-Kubernetes או ב-Cloud Run, והפעילו אותו: בדיקות תקינות, סבב סודות, שדרוגים ואבטחה.

[!NOTE]

תכננו קודם את הרשת של השער. בכניסה, Claude Code מסרב ל-Claude apps gateway שה-hostname שלו מפוענח לכתובת IP ציבורית, גם אם האינטרנט לא יכול להגיע אליה.

Claude apps gateway יכול לדחוף הגדרות למחשבים של משתמשים, כולל hooks שמריצים פקודות shell. הבדיקה עוזרת למנוע ממשתמשים להיכנס בטעות לשער זדוני באינטרנט הציבורי. השאירו גם את השער שלכם מחוץ לאינטרנט.

בחרו את הכתובת של השער לפני שאתם בוחרים איפה הוא רץ. בדרך כלל זו כתובת פרטית שמשתמשים מגיעים אליה ברשת הפנימית או דרך VPN. אם הרשת הפנימית משתמשת בטווחי IPv4 ציבוריים, אפשר לרשום טווח אחד שמכיל גם את השער וגם את המחשבים של המשתמשים. Claude Code מתייחס להתאמה הזו כסימן שהשער נמצא ברשת הפנימית שלכם. ראו בחירת כתובת לשער. אם אף אחת מהאפשרויות לא מתאימה לרשת שלכם, פנו לצוות החשבון של Anthropic.

הדף הזה עוסק בצד התפעולי של הרצת Claude apps gateway: רישום לקוח OAuth אצל ספק הזהויות (IdP), פריסת השער כקונטיינר, והרצה שלו ביום יום. לכל אפשרות בקובץ gateway.yaml שהשער קורא בעלייה, ראו את Configuration reference.

פריסת ייצור עוקבת אחרי ארבעה צעדים לפי הסדר, והסעיפים למטה תואמים אותם. בשניים הראשונים מקבלים החלטות. השניים האחרונים הם חומר עזר לעיון אחרי שהשער רץ.

  1. הגדרת ספק הזהויות: רישום לקוח ה-OAuth ובדיקת ההערות לפי IdP עבור Okta, Entra ו-Google
  2. פריסת השער: בניית תמונת קונטיינר נעולה לגרסה והרצה שלה ב-Kubernetes, ב-Cloud Run, או בפלטפורמה שלכם. הסעיף הזה מכסה גם החלטות על עלות, עקיפה, כמה שערים ו-serverless
  3. הגדרת תפעול: לוגים, בדיקות תקינות, התנהגות בהשבתה, סבב סודות ושדרוגים. חומר עזר כשמגדירים ניטור ו-runbooks
  4. סקירת מצב האבטחה: לאן הנתונים זורמים, מודל האיומים ותשובות לתאימות. חומר עזר לסקירת אבטחה

אם כניסה או עלייה נכשלות בדרך, עברו ישר אל Troubleshooting, שממוין לפי השגיאה שאתם רואים.

#הגדרת ספק הזהויות

רשמו יישום אינטרנט חסוי מסוג OAuth/OpenID Connect (OIDC) עם URI הפניה יחיד, https://<gateway>/oauth/callback, ושייכו אותו למשתמשים או לקבוצות שצריכים גישה לשער. השער מאמת את עצמו מול ה-IdP עם סוד הלקוח של הרישום, או עם אישור שאתם מעלים לרישום אם ה-IdP משתמש ב-certificate credentials במקום.

כל IdP תואם OIDC עובד: Okta, Microsoft Entra ID, Google Workspace, Keycloak, Dex, PingFederate ואחרים. ה-IdP חייב לעמוד בשלוש דרישות:

  • מגיש את /.well-known/openid-configuration, ב-HTTPS בייצור. השער מקבל מנפיק http://, ומנפיק loopback דורש בנוסף CLAUDE_GATEWAY_ALLOW_LOOPBACK=1
  • תומך בזרימת authorization-code. PKCE (Proof Key for Code Exchange) פועל כברירת מחדל. מבטלים אותו עם oidc.use_pkce: false עבור IdP שלא תומכים בו
  • מחזיר email ואופציונלית groups ב-id_token, או מגיש אותם מנקודת הקצה userinfo עם oidc.userinfo_fallback: true

עבור PKI פרטי, הגדירו oidc.ca_cert_pem.

כמה ספקים מטפלים אחרת בטענות email ו-groups:

  • Okta: שרת ההרשאות של הארגון ב-https://example.okta.com מחזיר id_token דק שמחסיר את email ואת groups, לכן הגדירו oidc.userinfo_fallback: true בכל פעם שמשתמשים בו כ-issuer. שרת הרשאות מותאם אישית כמו https://example.okta.com/oauth2/default שכולל email ואופציונלית groups ב-id_token פולט אותם ישירות ולא צריך fallback. Okta פולט groups רק כשה-scope groups מבוקש ב-oidc.scopes ומסנן טענת ה-groups של היישום מתיר זאת. userinfo_fallback לא יכול למלא טענה שה-IdP לא התבקש לספק.
  • Microsoft Entra ID: issuer = https://login.microsoftonline.com/<tenant-id>/v2.0. Entra פולט Object IDs של קבוצות ולא שמות, לכן השתמשו ב-GUID ב-managed.policies.match.groups, או השתמשו ב-App Roles לשמות קריאים לאדם. אם הדייר פולט תפקידים תחת roles במקום groups, הגדירו oidc.groups_claim: roles.
  • Google Workspace: issuer = https://accounts.google.com. ה-id_token של Google לא נושא groups. כדי להשתמש ב-allowed_groups או ב-managed.policies מבוססי קבוצה כש-Google הוא ה-IdP, הגדירו oidc.google_groups, שמאתר את הקבוצות של כל משתמש דרך Admin SDK Directory API באמצעות חשבון שירות עם domain-wide delegation. בלי זה, השתמשו ב-oidc.allowed_email_domains לשערי חברות וב-managed.policies.match.email_domain להקצאת מדיניות. Google גם מתעלם מ-scope הסטנדרטי offline_access. עבור refresh tokens, הגדירו oidc.scopes: [openid, profile, email] ו-oidc.extra_auth_params: { access_type: offline, prompt: consent }.

[!WARNING]

Refresh tokens מאפשרים לשער לחדש את הסשן של מפתח בשקט, בלי להחזיר את המפתח לדפדפן. הם גם מניעים ביטול הקצאה, כי כשה-IdP משבית משתמש, הרענון הבא נכשל והסשן מסתיים בתוך ttl_hours. השער מבקש offline_access כברירת מחדל כדי לקבל refresh token. אם ה-IdP דורש הסכמה מפורשת לגישה לא מקוונת, הגדירו את לקוח ה-OAuth כך שיתיר זאת.

אם ה-IdP לא יכול להנפיק refresh tokens בכלל, השער עדיין עובד, אבל אין חידוש שקט, ולכן מפתחים מריצים שוב את כניסת הדפדפן כשהסשן שלהם פג. כדי שזה לא יקרה כל שעה, העלו את session.ttl_hours ל-8 או ל-12. הפשרה היא השהיה בביטול ההקצאה, כי בלי refresh tokens משתמש מושבת שומר גישה עד שתוקף ה-TTL הארוך יותר חולף.

#פריסה

השער הוא בינארי Linux יחיד חסר מצב שמתאם דרך Postgres, אז פרסו אותו כמו כל שירות חסר מצב אחר בסביבה שלכם. השאירו אותו בתוך הרשת, במקום שבו המפתחים יכולים להגיע אליו ב-HTTPS והוא יכול להגיע ל-IdP, והתייחסו אליו כמו לכל שירות שמחזיק אישור ייצור.

כמה החלטות מעצבות את הפריסה מעבר למקום שבו הוא רץ:

  • עלות: אין רישיון נפרד ואין תשלום לפי מושב. השער הוא חלק מהבינארי claude, אז משלמים על הסקה דרך ההתחייבות הקיימת, ובנוסף על המחשוב שעליו הוא רץ.
  • עקיפה: השער לא אוכף שהמסלול היחיד למודל עובר דרכו. מפתח עם אישור משלו עדיין יכול לקרוא לספק ישירות, אז סגירת המסלול הזה היא החלטת מדיניות רשת, למשל חסימת egress אל api.anthropic.com חוץ מאשר מהשער. חסימת ה-egress הזה גם שוברת את WebFetch domain safety check, שקורא ל-api.anthropic.com מהמחשב של כל מפתח. הגדירו skipWebFetchPreflight: true במדיניות המנוהלת כדי לבטל אותו.
  • כמה שערים: כל אחד הוא פריסה נפרדת עם קונפיגורציה משלו, וה-CLI שומר אמון ואישורים לפי hostname של השער, כך שצוותים יכולים להשתמש בשערים שונים בלי התנגשות. כדי לשרת כמה מנפיקי OIDC, הריצו מופעים נפרדים.
  • Serverless: Cloud Run עובד אם מגדירים min-instances: 1 כדי להימנע מגילוי OIDC קר. Lambda ו-Cloud Functions לא עובדים, כי השער הוא שרת HTTP שרץ לאורך זמן.

כל טופולוגיית ייצור כאן שמה פרוקסי L7, כמו Ingress, החזית של Cloud Run, או ALB, לפני העתקים של HTTP רגיל. הגדירו listen.trusted_proxies לטווחי המקור של הפרוקסי כדי שהשער יקרא כתובות IP של לקוחות מ-X-Forwarded-For. השער מכבד את הכותרת רק כשעמית ה-TCP מהימן. לדוגמאות המעובדות של Google Cloud ושל AWS יש ערכים קונקרטיים לפי טופולוגיה. בלי פרוקסי מהימנים, כל בקשה נראית כאילו הגיעה מכתובת ה-IP של הפרוקסי, מה שמאחד מגבלות קצב לפי IP לדלי משותף אחד ורושם את כתובת ה-IP של הפרוקסי באירועי ביקורת.

אל תפנו בקשות לנקודות הקצה של device-authorization ושל token של השער, למשל עם שכתוב HTTP ל-HTTPS או קנוניזציה של host ב-ingress. Claude Code לא עוקב אחרי הפניות בבקשות האלה, ולכן כלל ingress שמפנה אותן שובר כניסה ורענון token.

תנו לפרוקסי כל idle timeout ארוך יותר ממרווח ה-keepalive של השער, שתלוי ב-upstream:

  • בכל upstream חוץ מ-provider: anthropic, השער כותב SSE ping אחרי שזרם היה שקט בערך 15 שניות.
  • ב-provider: anthropic, השער מעביר את התגובה בלי שינוי, כולל ה-pings של Anthropic API עצמו.

ברירת מחדל כמו 60 השניות של ה-ALB מספיקה כדי להשאיר זרם שקט פתוח. הדוגמה המעובדת של AWS מעלה אותו לשעה בכל מקרה, ושורת פתרון הבעיות שלה מכסה שערים ישנים מ-v2.1.229, שלא שלחו כלום בתקופות שקטות ב-upstreams שמקבלים עכשיו pings.

#בחירת כתובת לשער

Claude Code מקבל כתובת של שער באחת משתי דרכים:

  • כתובת פרטית: שימו את השער מאחורי מאזן עומסים פנימי או VPN, עם hostname שמפוענח רק לכתובות פרטיות, כמו RFC 1918 או CGNAT 100.64.0.0/10. המחשבים של המשתמשים יכולים להיות בכל כתובת. התנאי המקדים לרשת פרטית מפרט את הטווחים המקובלים.
  • בלוק מוצהר: אם הרשת הפנימית משתמשת במרחב IPv4 ציבורי שבבעלות הארגון, רשמו את הבלוק בהגדרה המנוהלת gatewayInternalNetworks. השער והמחשב של המשתמש חייבים שניהם להיות בתוך הבלוק הזה. ראו Allow a gateway on public address space you own.

אם אין בלוק יחיד שמכיל את שניהם, תנו לשער כתובת פרטית במקום.

#תמונת קונטיינר

בנו תמונה משלכם סביב הבינארי המקורי claude מההפצה הסטנדרטית של Claude Code:

  1. הורידו את בניית Linux לארכיטקטורה של התמונה מהפצה נעולה לגרסה. ראו Install a specific version לכתובת ההורדה.
  2. אמתו אותו מול manifest.json החתום ב-GPG של ההפצה, כמתואר ב-Binary integrity and code signing.
  3. העתיקו אותו אל הקשר הבנייה.

שקפו את ההפצה אל הרישום הפנימי אם הבניות לא יכולות להגיע למארח ההפצה, ונעלו את הגרסה שהצי רץ.

מעבר לבינארי, התמונה צריכה:

  • תמונה מבוססת glibc: התלויות הדינמיות היחידות של בניית glibc הן ספריות glibc. תמונות מבוססות Musl צריכות את הבנייה linux-x64-musl או linux-arm64-musl וחבילות נוספות. ראו Alpine Linux setup.
  • ספריית מצב ניתנת לכתיבה: השער רץ ככל משתמש, אבל לתמונות מינימליות אין home ניתן לכתיבה. הגדירו CLAUDE_CONFIG_DIR לנתיב ניתן לכתיבה כמו /tmp/.claude.
  • פקודת הקונטיינר: claude gateway --config /etc/claude/gateway.yaml, כשקובץ הקונפיגורציה מורכב לקריאה בלבד והסודות מסופקים כמשתני סביבה. השער מאזין ב-listen.port, ברירת המחדל 8080.

#Kubernetes

הריצו את השער כ-Deployment, כמו כל שירות חסר מצב:

  • הרכיבו את הקונפיגורציה מ-ConfigMap ואת הסודות מ-Secret. הפנו לסודות ב-YAML דרך ${file:/path/to/secret} או כמשתני סביבה
  • סיימו TLS ב-Ingress והגדירו listen.public_url ל-hostname של ה-Ingress
  • כוונו את בדיקת המוכנות אל GET /readyz ואת בדיקת החיוּת אל GET /healthz

לדוגמה מעובדת מלאה ב-AWS, שמכסה ECS Fargate או EKS, Amazon RDS ו-AWS Secrets Manager, ראו Deploy on AWS.

העדיפו את זהות עומס העבודה של הפלטפורמה על פני מפתחות סטטיים. ל-הפניית upstreams יש פרטי הגדרה לפי פלטפורמה. לצימוד בין עננים, כמו upstream של Amazon Bedrock על GKE, הגדירו אישורים מפורשים בבלוק auth של ה-upstream במקום.

#Cloud Run

הגדירו את השירות כך:

  • השאירו את listen.port בברירת המחדל 8080, שתואמת את PORT ברירת המחדל של Cloud Run, או הגדירו port: ${PORT}
  • הגדירו public_url למקור שניתן להגיע אליו מבחוץ. בייצור זה בדרך כלל hostname של מאזן עומסים פנימי, כי /login דוחה כתובות ציבוריות וכתובת *.run.app מפוענחת לכתובת כזו, כך שכתובת Cloud Run לבדה עובדת רק לבדיקת עשן ב-curl או בדפדפן. החריג הוא רשת שבה *.run.app מפוענח באופן פרטי דרך Private Service Connect ואזור DNS פרטי של Cloud DNS. בטופולוגיה הזו כתובת Cloud Run היא public_url תקין. הדוגמה המעובדת של Google Cloud מכסה את שניהם.
  • הרכיבו את הקונפיגורציה כנפח secret
  • הגדירו min-instances: 1 כדי להימנע מגילוי OIDC קר בבקשה הראשונה

לדוגמה מעובדת מלאה ב-Google Cloud, שמכסה Cloud Run או GKE, Cloud SQL ו-Secret Manager, ראו Deploy on Google Cloud.

#דחיפת כתובת השער למחשבי מפתחים

אחרי שהשער משרת, דחפו forceLoginMethod, forceLoginGatewayUrl ו-parentSettingsBehavior: "merge" לכל מחשב מפתח דרך הגדרות מנוהלות, באמצעות MDM או על ידי כתיבה ישירה של managed-settings.json לפי מערכת ההפעלה.

אחרי שפורסים את המפתחות, Claude Code מפסיק להשתמש במפתח API שנשאר או בכניסת claude.ai במחשב, אז תכננו את הדחיפה יחד עם הוראות הכניסה. Administrator policy requires a Cloud gateway sign-in מתאר את ההודעות שמפתחים רואים.

ראו where each mechanism stores the policy לנתיבי הקבצים, ו-Client-side managed settings למקביל bootstrapUrl של Claude Desktop.

#פריסות גדולות

הכניסה מוגבלת בקצב לפי כתובת IP של לקוח, וברירות המחדל מתאימות לצוות קטן. כל כתובת מקבלת 30 התחלות כניסה ו-10 שליחות קוד כל 10 דקות. פריסה לאלפי מפתחים יכולה להגיע למגבלות האלה בבוקר הראשון, מאחת משתי סיבות:

  • השער לא רואה מעבר למאזן העומסים. בלי listen.trusted_proxies, כל מפתח נראה כאילו הגיע מכתובת מאזן העומסים וחולק מגבלה אחת. הגדירו זאת לפני כל דבר אחר. השער רושם אזהרה בפעם הראשונה שהוא מתעלם מכותרת X-Forwarded-For.
  • מפתחים רבים חולקים כמה כתובות יציאה של NAT או VPN. הם חולקים את המגבלות של הכתובות האלה גם כש-trusted_proxies נכון. העלו את rate_limits כדי שיתאים.

כדי לקבוע את גודל max, חלקו את המפתחים בכתובות היציאה שהם חולקים. העריכו כמה מהם נכנסים בתוך תקופת window_seconds אחת, שהיא 10 דקות כברירת מחדל. אחר כך הכפילו כדי לכסות ניסיונות חוזרים ומפתחים שנכנסים גם ל-Claude Code וגם ל-Claude Desktop.

לדוגמה, 10,000 מפתחים מאחורי 4 כתובות יציאה נכנסים באופן שווה לאורך שעה. זה 2,500 מפתחים לכתובת וכ-420 מהם בכל 10 דקות, ואת זה מכפילים ומעגלים כלפי מעלה ל-1,000. הדוגמה למטה מגדירה את שתי המגבלות ל-1,000:

rate_limits:
  device_authorization: { max: 1000, window_seconds: 600 }
  device_verify: { max: 1000, window_seconds: 600 }

device_verify הוא מה שעוצר מישהו מלנחש את קוד הכניסה של מפתח אחר, אז העלו אותו רק עד כמה שההערכה צריכה. גם במגבלות האלה, קוד הוא 8 תווים מאלפבית של 20 תווים ופג אחרי 10 דקות, אז ניחוש נשאר לא מעשי. ראו User-code brute-force resistance.

כשה-IdP מנפיק refresh tokens, Claude Code מחדש סשנים בשקט, ואז אפשר להחזיר את המגבלה אחרי הפריסה. בלי refresh tokens, מפתחים נכנסים שוב כל session.ttl_hours. קבעו את גודל שתי המגבלות גם לקצב היציב הזה והשאירו אותן מועלות.

כשמגיעים למגבלה, Claude Code מגרסה v2.1.274 ואילך מציג The gateway is limiting sign-in attempts right now. שער בגרסה v2.1.274 ואילך מציג Too many attempts came from your network address בדף האימות, עם ההגדרות לבדיקה. הוא גם כותב שורת לוג sign-in refused שמציינת את ההגדרה לשינוי.

#תפעול

אחרי שהשער משרת תעבורה, התפעול ביום יום הוא קריאת הלוגים שלו, בדיקת התקינות שלו, וסבב הסודות שלו לפי לוח הזמנים שלכם. תת הסעיפים מכסים כל אחד מאלה, ובנוסף מה Postgres מחזיק ואיך שדרוגים וחזרות לאחור מתנהגים.

#יומנים

השער כותב שני זרמים אל stderr, ושניהם ידידותיים ל-JSON:

  • אירועי ביקורת: JSON בשורה אחת לכל אירוע שרלוונטי לאבטחה. העבר את stderr בצינור אל מאגד היומנים שלך.

    האירועים שנפלטים כוללים את config.load, session.mint, session.refresh, device.authorize, device.verify, device.callback, auth.denied, access.denied, access.public_client, inference, managed.serve, desktop_bootstrap.serve, desktop_bootstrap.denied, spend.blocked, admin.denied, admin.limit.upsert, ו-admin.limit.delete. השדות משתנים לפי האירוע:

    • אירועי mint ו-refresh מוצלחים נושאים את sub, email, client_ip, ואת התוצאה
    • auth.denied ו-access.denied נושאים את הסיבה ואת כתובת ה-IP של הלקוח, ובנוסף את נתיב הבקשה עבור auth.denied, כי אין זהות משתמש בסירובים האלה. שתי סיבות של access.denied משנות את מה שהאירוע נושא:
      • xff_unparseable: האירוע נושא גם את רשומת X-Forwarded-For שלא ניתן היה לקרוא
      • client_ip_unknown: האירוע לא נושא כתובת IP של לקוח, כי לחיבור לא הייתה כתובת עמית בזמן שרשימת access_control הייתה מוגדרת
    • access.public_client נושא את כתובת ה-IP של הלקוח של הבקשה הראשונה לכל תהליך שמגיעה מכתובת ציבורית בזמן ש-access_control.allow_cidrs ריק. השער מגיש את הבקשה כרגיל. האירוע מסמן שייתכן שהשער נגיש מהאינטרנט הציבורי. ראה את ההפניה של access_control לגבי מה נחשב ציבורי ולגבי רשימת ההיתר המומלצת.
    • inference רושם איזה upstream שירת את הבקשה ואת סטטוס התגובה
    • desktop_bootstrap.denied רושם שליפת bootstrap של Claude Desktop שנדחתה, עם הסיבה (not_configured, policy_not_opted_in, או no_policy_matched) ועם זהות המשתמש
    • guardrail.trace רושם איזה מסנן הופעל, בלי הטקסט שנמצאה לו התאמה
    • admin.denied רושם ניסיון אימות ל-API של ניהול שנדחה, עם כתובת ה-IP של הלקוח, השיטה, הנתיב, וסיבה, בלי חומר המפתח שהוצג: invalid_key כאשר הוצג x-api-key אבל הוא לא תאם שום מפתח מוגדר, bearer_rejected כאשר הוצגה רק כותרת Authorization והיא לא אומתה כהפעלת שער ב-admin.admin_groups, או no_credentials כאשר אף אחת מהכותרות לא הוצגה
  • יומנים תפעוליים: שורות קריאות לאדם עם קידומת [gateway] לאתחול, לאזהרות ולשגיאות upstream. משתנה הסביבה CLAUDE_GATEWAY_LOG_LEVEL שולט ברמת הפירוט ומקבל את debug, info, warn, או error, ו-info הוא ברירת המחדל. ב-debug, כל התחברות וכל רענון רושמים גם את השמות, לא את הערכים, של ה-claims ב-id_token, וגם את שמות ה-claims של userinfo כאשר userinfo_fallback סיפק כאלה, כדי שתוכל לאבחן את הגדרות email_claim ו-groups_claim בלי לרשום PII. זה לא משפיע על אירועי הביקורת, שנפלטים תמיד.

#בריאות

השער מגיש את GET /healthz כבדיקת חיות ואת GET /readyz כבדיקת מוכנות. /readyz מוודא שהמאגר נגיש. אם מגדירים את store.readiness_grace_seconds, /readyz ממשיך לדווח על מוכנות עד למספר השניות הזה אחרי שהמאגר מפסיק לענות.

שתי נקודות הקצה פטורות מ-access_control.allow_cidrs, כך שהבדיקות ממשיכות לעבוד על מאזין נעול.

מסמך הגילוי של OAuth ב-/.well-known/oauth-authorization-server גם מחזיר 200 רק אחרי שטעינת התצורה, גילוי OIDC, בניית לקוח ה-upstream, והמיגרציה של Postgres כולן מצליחות, ולכן הוא משמש גם כבדיקת אתחול מקצה לקצה.

#בקשות upstream בו זמנית

כברירת מחדל, כל עותק של השער שולח לכל היותר 256 בקשות אל upstream באותו זמן. תגובת הזרמה נספרת מול המגבלה עד שהזרם מסתיים.

בקשה שמגיעה בזמן שעותק נמצא במגבלה ממתינה בתוך השער לחריץ פנוי. המפתח רואה תגובה שמתחילה לאט או נראית תלויה. ב-upstream של provider: anthropic, בקשה שממתינה יותר מ-timeouts.upstream_ttfb_ms מוותרת על אותו upstream, ונכשלת עם 502 כאשר אין upstream מאוחר יותר שמגיש אותה.

שורת יומן האתחול שמכילה את upstream requests: מציגה את המגבלה שבתוקף. כאשר לעותק יש יותר בקשות פתוחות מהמגבלה, הוא גם רושם אזהרה שמכילה את client requests are open, לכל היותר פעם בדקה.

כדי לשרת יותר בקשות בבת אחת, יש שתי אפשרויות:

  • הוסף עותקים.
  • העלה את המגבלה בכל עותק. הגדר את משתנה הסביבה BUN_CONFIG_MAX_HTTP_REQUESTS על מכולת השער למספר שלם מ-1 עד 65535, ואז הפעל מחדש את המכולה.

עותק ממלא את המגבלה שלו בקצב בקשות של בערך המגבלה חלקי מספר השניות הממוצע שבקשה נשארת פתוחה. לדוגמה, אם בקשות נשארות פתוחות 10 שניות בממוצע, עותק במגבלת ברירת המחדל של 256 ממלא אותה בכ-26 בקשות בשנייה.

אם מבצעים התרחבות אוטומטית לפי CPU, עותק שנמצא במגבלה מעמיד בקשות בתור בלי להפעיל הרחבה, לכן הגדר את היעד מתחת לרמת ה-CPU שהעותקים מציגים כאשר הם רושמים את האזהרה client requests are open.

[!WARNING]

כל בקשה פתוחה מחזיקה זיכרון בתהליך השער בזמן שהיא מוזרמת ובזמן שהיא ממתינה לחריץ. אם משאירים את המגבלה על 256, הזיכרון בעותק בעומס יתר עדיין גדל, כי בקשות ממתינות שומרות את גופי הבקשה שלהן. קבע את זיכרון המכולה לפי מספר הבקשות הפתוחות בשיא, ועקוב אחרי הזיכרון כאשר משנים את המגבלה. עותק שנגמר לו הזיכרון נהרג ומפיל כל זרם שהוא מחזיק.

במבחן עומס עם load_test_mode, בקשות לא ממתינות במגבלה הזו, אבל עותק עדיין רושם את האזהרה client requests are open.

#שמור את API_TIMEOUT_MS מעל זמן הבייט הראשון של השער

אם מורידים את API_TIMEOUT_MS כדי לנסות שוב בקשה שלא נענתה מוקדם יותר, שמור אותו מעל הזמן שלוקח לשער לשלוח את הבייטים הראשונים של תגובת הזרמה. בקשה שממתינה יותר מזה מגיעה לפסק זמן, וכך גם כל ניסיון חוזר שממתין אותו זמן, עד שהסבב מסתיים ב-Request timed out אלא אם מועד הבייט הראשון מסיים אותו.

  • provider: anthropic: הגדר את API_TIMEOUT_MS מעל הזמן הארוך ביותר שלוקח ל-upstream שלך לשלוח את האירוע הראשון שלו.
  • כל upstream אחר: הגדר אותו ביותר מ-20 שניות מעל הזמן הארוך ביותר שלוקח ל-upstream שלך להחזיר כותרות תגובה. השער שולח את ה-ping הראשון לשמירת קשר כ-15 שניות אחרי הכותרות האלה, אלא אם האירוע הראשון של ה-upstream מגיע מוקדם יותר. שער ישן יותר מ-v2.1.229 לא שולח ping, לכן השתמש שם בכלל של provider: anthropic.

מעל הזמן הזה, התחשב בכל המתנה לחריץ פנוי ובהמתנה על upstream מושבת לפני מעבר לגיבוי. שמור את הערך גם מעל הבקשה הארוכה ביותר שאינה בהזרמה.

#נסה שוב בקשה שלא נענתה מוקדם יותר עם מועד הבייט הראשון

כדי לגרום ל-Claude Code לנסות שוב בקשת הזרמה שלא נענתה מוקדם יותר, תן לו מועד לבייט הראשון על ידי הגדרת CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS במכונות של המפתחים שלך. המועד מגביל כמה זמן הניסיון הראשון ממתין לכותרות תגובה. בלעדיו, הניסיון הזה יכול להמתין 5 עד 6 דקות. נדרש Claude Code v2.1.307 או חדש יותר במכונה של המפתח.

הגדר את המשתנה למספר שלם חיובי של אלפיות שנייה, בבלוק env של מדיניות שער או במעטפת של מפתח. שמור את הערך מעל זמן הבייט הראשון הארוך ביותר של השער שלך, אחרת Claude Code יכול לבטל ולשלוח מחדש בקשות תקינות שהכותרות שלהן לוקחות יותר זמן. הדוגמה הזו מגדירה 60 שניות במעטפת של מפתח:

export CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS=60000

שליחה מחדש שלא נענתה יכולה להמתין 5 עד 6 דקות, עד שפסק הזמן של חוסר פעילות בגוף מסיים אותה ו-Claude Code מנסה אותה שוב בתוך תקציב הניסיונות החוזרים. אם הורדת את API_TIMEOUT_MS רק כדי לנסות שוב מוקדם יותר, הסר את הערך הזה, אחרת שליחה מחדש אחת שלא נענתה יכולה לסיים את הסבב עם No response from API.

כדי לאשר שהמועד הופעל, בקש ממפתח להפעיל את Claude Code עם יומן ניפוי, ואז חפש ביומן את [first-byte] no response headers.

#התנהגות בזמן השבתה

אם Postgres יורד, השער עצמו ממשיך לשרת מפתחים מחוברים, והתחברויות חדשות נכשלות. האם מפתחים באמת ממשיכים לעבוד תלוי באופן שבו המתזמר שלך מטפל במוכנות:

  • הפעלות קיימות: אסימוני bearer מאומתים מקומית עם סוד ה-JWT, רענוני הפעלה לא נוגעים במאגר, ותהליך השער עדיין יכול לשרת היסק
  • התחברויות חדשות: נכשלות עד ש-Postgres מתאושש, כי זרימת המכשיר ומוני הגבלת הקצב שלה חיים ב-Postgres
  • אכיפת מגבלת הוצאה: נכשלת פתוחה כברירת מחדל במהלך ההשבתה, כך שההיסק עדיין זורם. הפוך אותה לכישלון סגור אם עדיף לחסום מאשר לרוץ בלי מדידה
  • מוכנות: כברירת מחדל /readyz מדווח על אי-מוכנות ברגע ש-Postgres לא נגיש, כך שכל עותק נכשל בבדיקת המוכנות בבת אחת. במקום שבו תעבורה מגיעה רק לעותקים שעוברים את הבדיקה, כל התעבורה, כולל היסק שהשער עדיין יכול לשרת, נכשלת עד ש-Postgres מתאושש. בדיקת החיות ב-/healthz ממשיכה לעבור לאורך כל הזמן.

אם ה-IdP יורד, הפעלות קיימות עובדות עד ttl_hours והתחברויות חדשות נכשלות. רענון הפעלה מקבל תשובת נסה שוב ומצליח ברגע שה-IdP חוזר. הגדר ttl_hours ארוך יותר אם ל-IdP יש חלונות תחזוקה תכופים.

#תקופת חסד למוכנות

כדי להשאיר מפתחים מחוברים בעבודה במהלך השבתת Postgres קצרה כגון מעבר כשל של מסד הנתונים, הגדר את store.readiness_grace_seconds לזמן ארוך יותר ממשך מעבר הכשל, לדוגמה 300. כאשר מגבלות הוצאה פעילות ועם התנהגות ברירת המחדל של כישלון פתוח, בקשות דרך עותק שנשאר מוכן הן בלי מדידה עד ש-Postgres מתאושש, לכן שמור את הערך נמוך ככל שהוא מכסה את מעבר הכשל שלך. אם מגדירים enforcement.fail_closed_on_error: true, השער מסרב להיסק של מפתחים מחוברים עם הודעת 429 spend limit unavailable עד ש-Postgres מתאושש, גם בזמן שהעותקים עדיין עוברים את בדיקת המוכנות.

ההגדרה דורשת Claude Code v2.1.282 או חדש יותר בשרת השער. שער מוקדם יותר מסרב להתחיל כאשר הוא מוצא את המפתח, לכן שדרג כל עותק לפני שמוסיפים אותו. שדרוגים מכסים חזרה לאחור.

אם מפנים את בדיקת המוכנות אל /healthz במקום זאת, העותקים גם ממשיכים לעבור אותה במהלך השבתה, אבל /healthz אף פעם לא מדווח על אי-מוכנות, כך שעותק שחיבור ה-Postgres שלו לא מתאושש ממשיך לעבור גם הוא.

#סיבוב סוד JWT

סובב את סוד החתימה בשלבים כדי שהפעלות קיימות יישארו תקפות:

  1. צור סוד חדש. הוסף אותו בתחילת מערך session.jwt_secret.
  2. גלגל את הפריסה. אסימונים חדשים נחתמים עם הסוד החדש. אסימונים ישנים עדיין מאומתים.
  3. אחרי ttl_hours ועוד מרווח, הסר את הסוד הישן וגלגל שוב.

הסיבוב הוא גם הדרך היחידה לכפות יציאת הפעלות לפני שהן פגות: אסימוני bearer מאומתים מקומית מול סוד ה-JWT, כך שאין ביטול לפי הפעלה. החלפת הסוד לגמרי, בלי להשאיר את הישן במערך, מבטלת כל הפעלה פתוחה בבת אחת. להוצאה מהמערכת של אדם בודד, בטל את הקצאת המשתמש ב-IdP שלך. ההפעלה שלו מסתיימת בתוך ttl_hours.

#Postgres

השער שומר את המצב שלו במסד נתונים PostgreSQL:

  • מסד נתונים: PostgreSQL עצמו, באירוח עצמי או מנוהל, בגרסת המינימום או מאוחר יותר. מסדי נתונים שמממשים רק את פרוטוקול Postgres, כגון מסדי SQL מבוזרים, אינם נתמכים.
  • כתובת: store.postgres_url מקבל מארח אחד. אם למסד הנתונים יש כמה צמתים, השתמש בכתובת שנמצאת לפניהם, כגון נקודת הקצה של השירות המנוהל, מאזן עומסים, או IP וירטואלי. הגדר תקופת חסד למוכנות ארוכה יותר ממשך מעבר כשל.

השער מחזיק חמש טבלאות נתונים ועוד טבלת _migrations, וכולן נוצרות על ידי המיגרציות בזמן האתחול:

טבלהתוכןשמירה
kvמענקי מכשיר (TTL של 10 דקות) ומוני הגבלת קצבTTL לכל שורה
spendמוני הוצאה עד כה בתקופה לפי principal, בסנטיםadmin.spend_retention_months, ברירת מחדל 13
spend_limitsתקרות הוצאה מוגדרותעד למחיקה דרך ה-API
admin_auditעקבות שינויים של API הניהולadmin.audit_retention_days, ברירת מחדל 365
principal_emailsהדוא"ל האחרון שנראה, שם התצוגה, וקבוצות ה-IdP של כל principal. מכיל PII.admin.identity_retention_days מאז הפעילות האחרונה, ברירת מחדל 90

לולאה של 30 שניות פוקעת שורות kv שעברו את ה-TTL שלהן, וסריקה שעתית אוכפת את חלונות השמירה על טבלאות ההוצאה, כך ששום דבר לא גדל בלי גבול. בלי מגבלות הוצאה מוגדרות, רק kv נכתבת. השער מפעיל את מיגרציות הסכמה שלו באתחול ובכל שדרוג, כך שתפקיד מסד הנתונים שלו צריך הרשאות ליצור ולשנות טבלאות. כוון אותו אל מסד נתונים או סכמה שמוקדשים לשער כדי לשמור על ההרשאה הזו צרה.

כאשר משתמשים במגבלות הוצאה, מסד נתונים שאבד פירושו אובדן מעקב הוצאה ותקרות, ולא רק התחברות מחדש של מפתחים, לכן הרץ גיבויים סדירים. כדי למחוק מפתח שעזב מיד במקום להמתין לשמירה, הרץ את DELETE FROM principal_emails WHERE principal = '<sub>' ישירות. זה מסיר את הטבלה היחידה שמחזיקה את הדוא"ל, השם, והקבוצות שלו. שורות spend ו-admin_audit מפנות רק אל sub הפסבדונימי של OIDC.

#גודל מאגר החיבורים

כל עותק פותח עד store.max_connections חיבורי Postgres, חמישה כברירת מחדל. שמור את מכפלת העותקים ב-store.max_connections ברמה של מספר החיבורים שנשארו למסד הנתונים עבור השער, או מתחתיו:

  • עותקים: ספור את המספר המרבי שרץ בבת אחת. התחל ממקסימום ההתרחבות האוטומטית, או ממספר העותקים אם אין התרחבות אוטומטית, והוסף את העותקים הנוספים שעדכון מתגלגל מתחיל לפני שהוא עוצר את הישנים. ב-Amazon ECS עם הגדרות ברירת מחדל, וב-Cloud Run, זה יכול להיות עוד אותו מספר.
  • חיבורים שנשארו: קח את max_connections של מסד הנתונים, ואז חסר את מה שמסד הנתונים שומר ואת מה שלקוחות אחרים מחזיקים. PostgreSQL שומר את superuser_reserved_connections, שלושה כברירת מחדל. שירות מנוהל יכול לשמור יותר, לכן בדוק את התיעוד שלו.

לדוגמה, קח מקסימום התרחבות אוטומטית של שישה, עדכונים מתגלגלים שמתחילים לכל היותר שני עותקים נוספים, ומאגר ברירת מחדל של חמישה. זה דורש (6 + 2) × 5 = 40 חיבורים. מסד נתונים עם max_connections של 50 ושני חיבורים שמוחזקים על ידי לקוחות אחרים משאיר 50 - 3 - 2 = 45, כך שהסך מתאים.

אם הסך שלך לא מתאים, שנה אחד מאלה:

  • מסד הנתונים: העלה את max_connections שלו
  • העותקים: הרץ פחות, או גרום למתזמר להתחיל פחות עותקים נוספים בעדכון מתגלגל
  • המאגר: הורד את store.max_connections, אבל כאשר מגבלות הוצאה פעילות, שמור אותו גדול מספיק לעומס של כל עותק. אחרת בדיקות הוצאה יכולות להגיע לפסק זמן בהמתנה לחיבור, והשער רושם spend check failed: spend precheck timed out.

#שדרוגים

הרפליקות חסרות מצב, ולכן הפעלה מחדש מתגלגלת לא מאבדת מצב של השער. השער מריץ מיגרציות סכמה בעלייה, כלומר פריסת הבינארי החדש מעדכנת את מסד הנתונים בעצמה. רפליקות מקבילות מסתדרות בתור על נעילת advisory של Postgres, כך שרק אחת מיישמת כל מיגרציה.

כשהמתזמר עוצר רפליקה עם SIGTERM, כמו בהפעלה מחדש מתגלגלת או בהקטנת קנה מידה, השער מפסיק לקבל חיבורים חדשים ונותן לבקשות ולזרמים שכבר בתהליך להסתיים לפני שהוא יוצא. הוא ממתין עד 25 שניות, שנקרא חלון הניקוז, ואז סוגר את מה שעדיין פתוח. SIGINT, כמו Ctrl+C במסוף, מתחיל את אותו ניקוז, ואות שני במהלך הניקוז סוגר את הבקשות הפתוחות ויוצא מיד. הניקוז דורש שער בגרסה v2.1.274 או חדשה יותר.

יצירות ארוכות יכולות לזרום במשך דקות. ב-Kubernetes וב-Amazon ECS, העלו את שני אלה יחד כדי לתת לזרמים האלה יותר זמן:

  • חלון הניקוז: הגדירו את משתנה הסביבה CLAUDE_GATEWAY_DRAIN_TIMEOUT_MS במכולת השער למספר שלם חיובי של אלפיות שנייה, כמו 120000. השער מתעלם מערך בכל צורה אחרת, כמו 120s, ושומר על ברירת המחדל של 25 שניות
  • תקופת החסד של המתזמר: terminationGracePeriodSeconds ב-Kubernetes, או stopTimeout ב-Amazon ECS

תקופת החסד היא 30 שניות כברירת מחדל בשתי הפלטפורמות. שמרו אותה לפחות 5 שניות ארוכה יותר מחלון הניקוז, אחרת המתזמר הורג את השער לפני שהניקוז מסתיים. ב-Kubernetes, הוסיפו גם את משך כל וו preStop, כי תקופת החסד מתחילה להיספר לפני שהוו רץ ולא כשהשער מקבל SIGTERM.

הפלטפורמה שלכם עשויה גם להגביל כמה זמן הניקוז יכול לרוץ:

  • Amazon ECS על Fargate: stopTimeout מאפשר לכל היותר 120 שניות
  • Cloud Run: עוצר מופע 10 שניות אחרי SIGTERM, כך שזרמים פתוחים מקבלים שם לכל היותר 10 שניות, יהיה חלון הניקוז אשר יהיה

כשחלון הניקוז מסתיים ועדיין יש בקשות פתוחות, השער רושם אזהרה שמכילה drain window over after, סופר את הבקשות שחתך, ומציין את שתי ההגדרות שיש להעלות.

המיגרציות הן תוספת בלבד, ולכן חזרה לבינארי קודם שמכיר פחות מיגרציות בטוחה. הוא מתעלם מהשורות העודפות. החזרה גם מאמתת מחדש את ה-YAML מול הסכמה של הבינארי הישן, כך שתצורה שאימצה מפתח שהגרסה החדשה הכניסה נכשלת בעלייה על הישן. הסירו את המפתח החדש לפני החזרה.

[!WARNING]

הסרה של מפתח groups בלבד מ-upstream משאירה אותו פתוח לכל מפתח. ראו מה להסיר לפני שחוזרים אחורה.

מכיוון שאתם מקבעים את גרסת השער בתמונה שלכם, תיקונים במהדורות חדשות של Claude Code, כולל תיקוני אבטחה, מגיעים לפריסה שלכם רק כשאתם מעדכנים את הקיבוע ופורסים מחדש. כללו את השער באותו קצב תיקונים שבו אתם משתמשים לשירותים אחרים שמחזיקים אישורי ייצור.

#אבטחה

הקטע הזה עונה על השאלות שסקירת אבטחה שואלת: אילו נתונים זורמים דרך השער ולאן הם הולכים, מפני אילו מתקפות העיצוב מגן, ואילו תשובות שייכות לשאלון ציות.

#זרימת נתונים

נתוןנתיבנשלח ל-Anthropic על ידי השער
הסקה (פרומפטים, השלמות)CLI → gateway → ה-upstream שלכםרק אם Anthropic API הוא upstream מוגדר
טלמטריה (מדדי OTLP, ועוד יומנים ועקבות בהצטרפות)CLI → gateway → האספן שלכםלעולם לא
זהות (email, groups, sub)IdP → gateway → CLI. ה-CLI מטביע אותה על ייצואי OTLP. אם מפעילים forward_user_identity, השער גם שולח את כתובת הדוא"ל של המפתח ואת ה-subject של ה-IdP ככותרות אל הפרוקסי שלכםלעולם לא
הגדרות מנוהלותה-YAML של השער שלכם → CLIלעולם לא
יומן ביקורתstderr של השער → האגרגטור שלכםלעולם לא

#סיכום מודל האיומים

השער יושב בתוך היקף הרשת שלכם, אבל מחשבים ניידים של מפתחים בודדים לא נחשבים מהימנים. העיצוב מביא זאת בחשבון בשלוש דרכים:

  • מפתחים מחזיקים JWT קצרי חיים במקום מפתחות upstream גולמיים. המקטע מ-CLI אל השער משתמש ב-device grant של RFC 8628, וחילופי קוד ההרשאה של השער עם ה-IdP מריצים PKCE בתצורת ברירת המחדל, כך שקוד הרשאה של IdP שיירט חסר תועלת.

  • עמוד אימות המכשיר אוכף POST מאותו מקור ומגבלת קצב לפי IP לפי RFC 8628 §5.1. ראו עמידות בכוח גס של קוד משתמש.

  • הבקשות של השער אל ה-IdP שלכם, אל אספני ה-OTLP שלכם, ואל upstreams של provider: anthropic עוברות דרך שומר זיוף בקשות בצד השרת (SSRF) שפותר DNS, חוסם כתובות link-local וכתובות מטא-נתונים של ענן וגם loopback כברירת מחדל, ומצמיד את החיבור ל-IP שנפתר, כך שכתובות URL שמושפעות מהמפעיל לא יכולות להיות מופנות לנקודות קצה של מטא-נתוני ענן. טווחים פרטיים של RFC 1918 מותרים בכוונה, כי IdP ואספני OTLP נמצאים בדרך כלל על כתובות IP פרטיות. עבור הספקים האחרים, השער מסרב ל-base_url שמציין אחת מהכתובות האלה או שם מארח מטא-נתונים כשהוא טוען את התצורה, ו-SDK של הספק מתחבר אחר כך בלי בדיקת ה-DNS.

    אם מפעילים יציאה דרך פרוקסי בלבד, בדיקת הכתובת עוברת לפרוקסי הקדמי שלכם: השער מוסר לו שמות מארח ורשימת ההיתר של הפרוקסי חייבת לסרב ליעדים האלה.

    הגדירו CLAUDE_GATEWAY_ALLOW_LOOPBACK=1 בסביבת השער רק כשמשהו שהשער חייב להגיע אליו באופן לגיטימי נמצא על loopback, כמו IdP לפיתוח מקומי או אספן OTLP מסוג sidecar על localhost. המשתנה מרפה את חסימת ה-loopback לכל URL שהמפעיל הגדיר וגם מדלג על אזהרת העלייה שבודקת אם ה-pod יכול להגיע לנקודת הקצה של מטא-נתוני הענן, ולכן עדיף לתת לאספן כתובת פנימית משלו.

אם מוסיפים בקרות יציאה משלכם, השער חייב להגיע לשרת המטא-נתונים בכל פעם שהוא משתמש באישורי מטא-נתונים של מופע כמו workload identity.

שני איומים מחוץ לתחום כי הם התשתית שלכם לאבטח:

  • מארח שער שנפרץ: המארח גם מחזיק את אישור ה-upstream וגם מפיץ הגדרות מנוהלות לכל מפתח מחובר, כך ששליטה בתצורת השער דומה לשליטה ב-MDM שלכם. תיבת האישור של ה-CLI להגדרות עם יכולת shell מגבילה שינויים שקטים אבל לא מחליפה אבטחת מארח.
  • ספק OIDC זדוני: הספק חותם על ה-id_tokens שהשער סומך עליהם, ולכן הוא יכול לטעון לכל זהות. בדיקה ואבטחה של ה-IdP שלכם הן באחריותכם.

#עמידות בכוח גס של קוד משתמש

ה-user_code שמפתח מקליד בעמוד האימות /device הוא 8 תווים שנמשכים מאלפבית של 20 תווים, מה שנותן 20⁸ או בערך 2.56×10¹⁰ צירופים, והוא פג אחרי 10 דקות.

השער מחיל מגבלות קצב לפי IP על נקודות הקצה של device grant, שניתן להגדיר דרך rate_limits. העלו את המגבלות אם מפתחים רבים נכנסים מכתובת NAT ארגונית משותפת אחת. פריסות גדולות מראה איך לתת להן גודל. המגבלות חלות רק על תהליך הכניסה, לא על הסקה.

#מצב ציות

  • תושבות נתונים: מישור הנתונים של השער עצמו לא שולח דבר ל-Anthropic אלא אם Anthropic API הוא upstream מוגדר. כשכן, הסכם הטיפול בנתונים הקיים שלכם חל על נתיב ההסקה. טלמטריה, ביקורת, זהות והגדרות הולכות רק ליעדים שאתם מגדירים.
  • תעבורת תהליך המארח: תהליך המארח הוא ה-CLI של Claude Code. claude gateway רץ תחת אותם כללי צד שלישי כמו פריסות Amazon Bedrock ו-Agent Platform של Google Cloud ולא שולח דבר ל-Anthropic. לפני v2.1.227, תהליך המארח שלח טלמטריית עלייה כמו גרסת מוצר ופלטפורמה, שהגדרת CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 בסביבת המכולה כיבתה. המהדורות האלה גם שלחו בקשת HEAD אחת בעלייה, בלי גוף או אישורים, אל /api/hello על https://api.anthropic.com, או על ANTHROPIC_BASE_URL כשהסביבה הגדירה אותו, אלא אם הסביבה גם הגדירה משתנה פרוקסי כמו HTTPS_PROXY או אישור לקוח mTLS. הן התעלמו מהתשובה, כך שחסימת הבקשה הזו בחומת האש של היציאה לא השפיעה על השער.
  • ניתוח לקוח: ה-CLI מכבה את ניתוח השימוש ודיווח השגיאות שלו בזמן שהוא מחובר לשער. לפני הכניסה הראשונה, ה-CLI עדיין שולח אירועי עלייה ל-Anthropic, כולל במכונות שההגדרות המנוהלות שלהן כופות כניסה לשער. כדי לכבות גם את אלה, מסרו DISABLE_TELEMETRY באותן הגדרות מנוהלות בצד הלקוח שכופות כניסה לשער.
  • דיווח שגיאות: ה-CLI מכבה דיווח שגיאות בכל פעם שבקשות המודל שלו הולכות לכל נקודת קצה שאינה ה-API ממקור ראשון של Anthropic, כמו Amazon Bedrock או ANTHROPIC_BASE_URL מותאם.
  • מכונות לקוח: ה-CLI של המפתחים עדיין שולחים בדיקות שם מארח של WebFetch ובדיקות גרסה ל-Anthropic אלא אם CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 ו-skipWebFetchPreflight: true מוגדרים. לבקשות שוק התוספים יש מתגי כיבוי משלהן. ראו שימוש בנתונים.
  • דירוגי סקר: בזמן חיבור לשער, ה-CLI מכבה את העלאת הדירוג אל Anthropic יחד עם זרמי הניתוח, כך שהוא לא שולח דירוגים ל-Anthropic.
  • שיתוף תמליל: בחירה ב-Yes בהנחיית שיתוף התמליל של סקר כותבת קובץ מקומי תחת ~/.claude/feedback-bundles/ במקום להעלות ל-Anthropic.
  • עדכוני לקוח: בדיקות עדכון נפרדות מתעבורת השער. קבעו גרסאות דרך ההפצה שלכם והגדירו DISABLE_UPDATES אם מחשבים ניידים לא אמורים למשוך מהדורות. DISABLE_AUTOUPDATER עוצר רק עדכוני רקע בעוד claude update עדיין עובד.
  • TLS: הגישו public_url מעל HTTPS בייצור, או מהמאזין של השער עצמו דרך listen.tls או מ-ingress שמסיים TLS מול רפליקות HTTP פשוט, עם listen.public_url מוגדר בשני המקרים. השער לא מסרב ל-HTTP פשוט. ה-IdP חייב להגיש HTTPS בייצור, ו-Postgres תומך ב-?sslmode=require. הגדירו Strict-Transport-Security ב-ingress שלכם.
  • גילוי פגיעויות: עקבו אחר דיווח על בעיות אבטחה

#בקשות שוק התוספים

Claude Code מביא שוקי תוספים ישירות מהמכונה של כל מפתח, לא דרך השער. דרישות גישה לרשת מפרטות את המארחים.

בפעם הראשונה שמפתח מתחיל הפעלת מסוף אינטראקטיבית, Claude Code רושם את השוק הרשמי, claude-plugins-official. הוא מוריד את הקטלוג מ-downloads.claude.ai, ואם זה נכשל, משכפל אותו מ-github.com. אילו שווקים ותוספים מתעדכנים אוטומטית מכסה רענונים מאוחרים יותר.

CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 לא עוצר את הרישום הראשון. אחת מההגדרות המנוהלות האלה כן עוצרת:

  • רשימת שווקים: רשימת היתר strictKnownMarketplaces שמשאירה את השוק בחוץ, או רשומת blockedMarketplaces שמציינת אותו
  • משתנה סביבה: CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL מוגדר ל-"1" בבלוק env המנוהל

הרישום הראשון יכול לרוץ לפני שהמפתח נכנס לשער, כשאף מדיניות שער לא הגיעה. כדי לכסות את ההתחלה הראשונה הזו, מסרו את הבחירה שלכם בהגדרות מנוהלות בצד הלקוח וגם בבלוק cli או code של מדיניות השער.

#פתרון בעיות

לשאלות ומשוב, השתמשו בתמיכת Claude Code, או פתחו issue במאגר GitHub של Claude Code. אפשר גם לפנות לצוות החשבון של Anthropic שלכם. כשמדווחים על בעיה, כללו:

  • בעיית שער: ה-stderr של השער לחלון הרלוונטי, ה-gateway.yaml שלכם עם סודות מושחרים, גרסת השער, שמוצגת בעמוד הנחיתה ב-/ ובכותרת התשובה x-cc-gateway-version על /managed/settings, ומה השתנה לאחרונה
  • בעיית כניסה: המפתח מריץ claude --debug-file ./claude-debug.txt, משחזר, ושולח את הקובץ הזה ועוד את יומן הביקורת של השער לאותו חלון
  • בעיית הסקה: המודל שהתבקש, ה-upstreams שהוגדרו, ויומן הביקורת של השער לבקשה, שרושם איזה upstream שירת אותה ואת סטטוס התשובה

ה-stderr של השער כולל את זרם אירועי הביקורת, יומן הביקורת רושם זהויות מפתחים, וקובץ הדיבוג רושם פלט של hook ושרת MCP מהמכונה של המפתח. סקרו והשחירו אותם לפני פרסום ב-issue ציבורי.

תסמיןסיבהתיקון
אצל מפתח, /login מציג את בורר החשבונות הרגיל במקום את מסך Cloud gatewayforceLoginMethod או forceLoginGatewayUrl לא מוגדרים בהגדרות המנוהלות במחשב הזהפרוס את קובץ ההגדרות המנוהלות למכשיר. /login קורא משם את כתובת ה-gateway
הבקשות של מפתח נכשלות עם Not signed in to the Cloud gateway , run /login.ההגדרות המנוהלות של המחשב מגדירות forceLoginMethod: "gateway" או forceLoginGatewayUrl, ואין בסשן כניסה ל-gateway. כניסה ישנה ל-claude.ai לא מספקת את הדרישה.בקש מהמפתח להריץ /login ולהשלים את הכניסה ל-gateway. ראה גם Administrator policy requires a Cloud gateway sign-in.
Claude Desktop מדווח שלא ניתן היה למשוך את תצורת ה-bootstrap שלו/user/bootstrap החזיר 404: המדיניות שתואמת למשתמש לא נושאת מפתח desktop, או שאף מדיניות לא תאמה. יומן הביקורת של ה-gateway רושם כל דחייה כ-desktop_bootstrap.denied עם הסיבה.הוסף בלוק desktop למדיניות שתואמת למשתמש, או לשכבת הבסיס match: {}. מספיק desktop: {} ריק. ראה Claude Desktop overlay.
יומן הביקורת מציג auth.denied עם reason: invalid_token על /v1/logs או /v1/metricsהגדרת otelHeadersHelper בהגדרות המנוהלות של מחשב. בסשן Claude Desktop במחשב הזה, Claude Code שולח את כותרת Authorization מה-helper אל ממסר הטלמטריה של ה-gateway במקום אסימון הסשן. כש-Claude Desktop אורז את Claude Code מלפני v2.1.307, מתקבלת אותה דחייה אם מגדירים כותרת Authorization ב-OTEL_EXPORTER_OTLP_HEADERS או בצורה לפי אות בהגדרות האלה.הסר את ה-helper מההגדרות האלה. כש-Claude Desktop אורז את Claude Code מלפני v2.1.307, הסר את המשתנה.
בהפעלה מופיע Gateway login is configured in managed settings, but this Claude Code build does not include Cloud gateway support.גרסת Claude Code המותקנת קודמת לתמיכה ב-gatewayבקש מהמפתח לעדכן את Claude Code לגרסה שכוללת תמיכה ב-Cloud gateway
ההפעלה יוצאת עם Administrator policy requires a Cloud gateway sign-in on this machineהסביבה של המפתח מגדירה ANTHROPIC_API_KEY או ANTHROPIC_AUTH_TOKEN, ההגדרות שלו מגדירות apiKeyHelper, או שמפתח API מכניסה קודמת ל-Claude Console עדיין שמורבקש מהמפתח לנקות כל מה שחל: לבטל את המשתנה, להסיר את רשומת apiKeyHelper, או להריץ claude auth logout כדי להסיר את המפתח השמור. סשן שבוחר ספק ענן עם CLAUDE_CODE_USE_* מתחיל בלי כניסה. לכל סשן אחר, בקש להפעיל את claude ולהיכנס עם /login. ראה גם Administrator policy requires a Cloud gateway sign-in.
ההפעלה או /login מדווחים Claude Code may not be enabled for your organization אחרי 403 בטעינת ההגדרות המנוהלותה-gateway, או משהו לפניו, ענה לבקשת /managed/settings ב-403. נתיב ההגדרות של ה-gateway עצמו אף פעם לא עונה 403. הסטטוס מגיע מבדיקות ה-IP של access_control או מפרוקסי או WAF לפני ה-gateway. יומן הביקורת רושם דחיית בדיקת IP כ-access.denied עם הסיבה. המפתח נשאר מחובר.בדוק ביומן הביקורת access.denied בזמן הכשל ותקן את רשימות access_control או את החזית, ואז בקש מהמפתח להפעיל את claude שוב
CLI /login: The gateway is limiting sign-in attempts right now, או Request failed with status code 429 בגרסאות ישנות יותר. דף /device עשוי להציג Too many attempts למפתחים שעוד לא ניסומגבלת קצב הכניסה לפי IP הושגה. או ש-listen.trusted_proxies לא מכסה את מאזן העומס, ולכן כל המפתחים חולקים את הכתובת שלו, או שמפתחים רבים חולקים כתובת יציאה של NAT או VPN. אירועי ביקורת עם result: rate_limited מציגים את אותם ערכי client_ip אחד או מעטים.הגדר קודם את listen.trusted_proxies לטווחי המקור של מאזן העומס, ואז העלה את rate_limits אם המפתחים עדיין חולקים כתובות. ראה Large rollouts.
CLI /login: Gateway hosts must be on your organization's private network; <host> resolves to the public (or unrecognized) address <ip>שם המארח של ה-gateway מפוענח לכתובת IP ציבורית אחת לפחות. Claude Code בודק כל כתובת שפוענחה ודורש שכל אחת תהיה פרטית. סיבה נפוצה היא שם dual-stack שבו משפחה אחת מפוענחת לכתובת ציבורית, כולל מאזני עומס dual-stack פנימיים של AWS, שמחזירים כתובות AAAA בטווח ציבורי.דאג ששם ה-gateway יפוענח רק לכתובות פרטיות במחשבי המפתחים. לשם dual-stack, הסר את רשומת הטווח הציבורי או הגש שם DNS נפרד פנימי בלבד. ראה את התנאי המקדים של רשת פרטית. אם הכתובת היא מרחב ציבורי שהארגון שלך בבעלותו ומשתמש בו פנימית, הצהר על הבלוק הזה במקום.
CLI /login: Gateway login would go through proxy <proxy>, which is not on a private networkHTTPS_PROXY או HTTP_PROXY חלים על מארח ה-gateway, ושם המארח של הפרוקסי מפוענח לכתובת ציבורית. פרוקסי שהמארח שלו מפוענח רק לכתובות פרטיות מותר ולא מפעיל את השגיאה הזוהוסף את מארח ה-gateway ל-NO_PROXY במחשב המפתח כדי שהחיבור יהיה ישיר, או השתמש בפרוקסי ששם המארח שלו מפוענח לכתובות פרטיות. ההודעה מציינת את רשומת NO_PROXY המדויקת שיש להוסיף
CLI /login: Claude Code only signs in to <host> from inside its declared network <block> (managed settings), and this machine is connecting from <ip>, outside itה-gateway נמצא בבלוק שהוצהר ב-gatewayInternalNetworks, והמחשב של המפתח הגיע אליו מכתובת מחוץ לבלוק הזה: מאגר כתובות VPN, מקטע NAT של קונטיינר או WSL2, או רשת שאינה שלךבקש מהמפתח להריץ /login ממערכת ההפעלה המארחת ברשת שלך. אם הכתובת שמוצגת היא גם מרחב ציבורי של הארגון שלך, החלף את רשומת ה-gateway בבלוק שמכסה את שניהם, עד /8. רשומה שנייה חופפת נדחית. אם אין בלוק שמכסה את שניהם, ראה Choose an address for the gateway
CLI /login: Every address for gateway host <host> must be inside its declared network <block>, and it also resolves to <ip>השם של ה-gateway מפוענח לכתובת מחוץ לבלוק שהוצהר ב-gatewayInternalNetworks: אתר שני, או רשומת IPv6 בשם dual-stack. תחת בלוק מוצהר כל רשומה חייבת להיות בתוך בלוק ה-IPv4 האחד הזה, כולל כתובות פרטיות וכתובות IPv6פרסם במחשבי המפתחים רק רשומות בתוך הבלוק עבור שם ה-gateway, או הגש שם פנימי בלבד נפרד
CLI /login: <host> is on the declared network <block>, which Claude Code checks over a direct connection, not through an HTTP proxyHTTPS_PROXY או HTTP_PROXY חלים על gateway בבלוק מוצהרבמחשב המפתח, הוסף את רשומת NO_PROXY שההודעה מציינת
CLI /login: הודעה שמתחילה ב-gatewayInternalNetworks in managed settingsהערך שובר אחד מכללי האימות, וההודעה מציינת איזה. עד שמתקנים אותו, Claude Code מסרב לכל /login חדש ל-gateway במחשב, כולל gateways בכתובות פרטיות. כניסות קיימות ממשיכות לעבודבמקור ההגדרות המנוהלות שאתה פורס, תקן את הרשומה שההודעה מציינת, ואז הרץ שוב /login
CLI /login: Could not resolve the configured HTTP proxyשם המארח ב-HTTPS_PROXY או HTTP_PROXY לא מפוענח ממחשב המפתח, בדרך כלל כי הוא לא מחובר לרשת הארגוניתבקש מהמפתח להתחבר לרשת או ל-VPN שלך ולנסות שוב, או תקן את כתובת הפרוקסי
CLI /login: Could not resolve gateway host <host>המחשב לא יכול לפענח את שם ה-DNS הפנימי של ה-gateway, בדרך כלל כי הוא לא ברשת הארגוניתבקש מהמפתח להתחבר לרשת או ל-VPN שלך, ואז לנסות שוב /login
האתחול יוצא עם שגיאת אימות תצורה שמציינת store.postgres_urlPostgres לא מוגדר. ה-gateway דורש Postgresהגדר store.postgres_url. לפיתוח מקומי, השתמש בקונטיינר חד פעמי: docker run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust postgres.
האתחול יוצא: store.postgres_url in <path> is not a URL the gateway can read, או לפני v2.1.290 Invalid URL או URI error חשופיםאי אפשר לנתח את ה-URL, למשל כי הוא מציין יותר ממארח אחד או שהסיסמה שלו מכילה /, ?, # או % לא מקודדיםציין מארח אחד, והעבר את הסיסמה אל store.password
האתחול יוצא: requires the native binaryריצה תחת Node במקום הבינארי המקוריהתקן את Claude Code באחת משיטות ההתקנה העצמאיות
האתחול יוצא עם שגיאת גילוי OIDC אחרי config.loadoidc.issuer לא נגיש, או שרשרת ה-TLS לא מהימנהבדוק שהמנפיק נגיש מה-pod ומגיש /.well-known/openid-configuration. הגדר ca_cert_pem עבור PKI פרטי. אם ה-pod מגיע ל-IdP רק דרך forward proxy, הגדר oidc.use_proxy: true. בגרסאות לפני v2.1.227, תן ל-pod מסלול ישיר לכל אחד מנקודות הקצה של ה-IdP במקום זאת. אם ה-pod גם לא יכול לפענח את שם המארח של ה-IdP, או שהפרוקסי מסרב ל-CONNECT אל כתובת IP, ראה Proxy-only egress, שדורש v2.1.277 או חדש יותר.
האתחול יוצא עם שגיאת הרשאת Postgresלתפקיד מסד הנתונים חסרות זכויות DDL על הסכמה שלוהענק לתפקיד CREATE על הסכמה של ה-gateway כדי שיוכל ליצור ולשנות את הטבלאות שלו באתחול
יומן: remaining connection slots are reserved או sorry, too many clients already, מ-PostgreSQL. זה מופיע באזהרות postgres connection closed של רפליקות שרצות, או ביומן האתחול של רפליקה חדשה. שם, remaining connection slots are reserved יכול להופיע אחרי attempt 1 of 3, והרפליקה עדיין עשויה לעלות.הרפליקות מבקשות יותר חיבורים ממה שנשאר למסד הנתונים עבור ה-gateway, ו-PostgreSQL מסרב לעודפיםהתאם את הסך הכולל, כפי שSize the connection pool מתאר: הרץ פחות רפליקות, הורד את store.max_connections, או העלה את max_connections של מסד הנתונים. אם הסך הכולל מתאים חוץ מבזמן עדכון מתגלגל, אפשר במקום זאת שהמתזמר יעצור רפליקה ישנה לפני שהוא מפעיל חדשה, אם הוא תומך בכך.
יומן: could not connect to Postgres at boot, attempt 1 of 3, עם סיבה שאינה remaining connection slots are reservedמסד הנתונים עוד לא היה נגיש כשה-gateway עלה, למשל במופע קר שהרשת שלו עדיין עולהאם ה-gateway מסיים אחר כך את האתחול, אין צורך בפעולה. כשמסד הנתונים לא נגיש, ה-gateway מנסה את החיבור שלוש פעמים, בהפרש של שתי שניות, לפני שהוא יוצא. אם הוא יוצא עם could not connect to Postgres, בדוק את store.postgres_url, כולל שהוא מציין מארח אחד, ואת נתיב הרשת אל מסד הנתונים. אם הניסיונות מגיעים ל-timeout ולא נדחים, העלה את store.connect_timeout_seconds כדי לתת לכל אחד יותר זמן.
יומן: Postgres <version> is below the supported floorמסד הנתונים מריץ גרסת PostgreSQL ישנה יותר ממה שגרסת ה-gateway שלך תומכת בה. ה-gateway ממשיך לרוץ.שדרג את מסד הנתונים. ב-PostgreSQL 11, 12 או 13, אפשר במקום זאת לשדרג את ה-gateway כדי לעמוד בדרישת PostgreSQL.
/oauth/callback מציג "Sign-in could not be completed"דומיין האימייל נדחה, אימות id_token נכשל, או ש-email_verified הוא במפורש false, וה-gateway תמיד דוחה זאת בלי אפשרות עקיפהבדוק את allowed_email_domains ושה-IdP מחזיר claim של email מאומת. עבור email_verified: false, תקן את האימות בצד ה-IdP. אם ה-IdP פולט אימייל תחת שם claim אחר, הגדר oidc.email_claim.
יומן: token exchange failed request_id=<id>: id_token missing email claimה-IdP לא כולל email ב-id_token כברירת מחדל. הדחייה הזו נורה רק כש-allowed_email_domains מוגדר. בלעדיו, אימייל חסר יוצר סשן בלי אימיילהגדר את ה-IdP לפלוט email ב-id_token. Okta: הוסף email ל-claims של ID token בשרת הרשאה מותאם. Entra: הוסף email כ-claim אופציונלי ברישום האפליקציה. PingFederate: הפעל מדיניות OpenID Connect שפולטת email. אם ה-IdP מגיש email מנקודת הקצה userinfo אבל לא יכלול אותו ב-id_token, כמו שרת ההרשאה של ארגון Okta, הגדר oidc.userinfo_fallback: true.
יומן: refresh failed request_id=<id>: invalid_token (…) (at userinfo_no_id_token, …), ומפתחים רואים Cloud gateway session expired כל session.ttl_hoursה-IdP קיבל את אסימון הרענון אבל לא החזיר איתו id_token, ולכן ה-gateway שאל את נקודת הקצה userinfo של ה-IdP על ה-claims של המשתמש. ה-IdP דחה שם את אסימון הגישה המרוענן. ה-gateway עונה temporarily_unavailable, ולכן Claude Code שומר את אסימון הרענון אבל לא יכול לחדש את הסשן. גרסאות gateway לפני v2.1.260 רושמות את אותה שורה בלי פירוט (at …).הגדר oidc.scope_on_refresh: true, זמין ב-gateway v2.1.260 או חדש יותר, כדי שבקשת הרענון תבקש שוב openid. חלק מה-IdP, כמו Okta, מחזירים id_token ברענון רק כשמבקשים. ב-PingFederate, הפעל את Return ID Token On Refresh Grant תחת Applications > OAuth > OpenID Connect Policy Management במקום זאת. המפתח לא משנה את ההתנהגות של PingFederate. עבור IdP אחרים שעדיין משמיטים אותו, בדוק אם נקודת הקצה userinfo מקבלת אסימוני גישה שהונפקו מרענון. כפתרון זמני, העלה את session.ttl_hours. ראה Identity provider setup לגבי פשרת ביטול ההקצאה.
מפתח נכנס, ואז כל בקשה מהסשן הזה נכשלת עם שגיאת 431אסימון הסשן בכותרת Authorization של כל בקשה מפרט את קבוצות ה-IdP של המפתח, ולכן אצל מפתח בהרבה קבוצות הכותרות יכולות להגיע יחד ליותר ממה שה-gateway מקבלראה Request headers too large after sign-in לגבי איזו מגבלה חלה ומה לשנות
כל בקשת Amazon Bedrock מחזירה 502. היומן מציג Could not load credentials from any providersב-EC2, מגבלת ה-hop של IMDSv2 כברירת מחדל, 1, חוסמת את בקשת המטא-דאטה של המופע מתוך הקונטיינר. האתחול ו-/readyz עוברים בכל זאת כי AWS SDK פותר את אישורי המופע בבקשה הראשונה, לא בבניית הלקוחהעלה את מגבלת ה-hop עם aws ec2 modify-instance-metadata-options --instance-id <id> --http-put-response-hop-limit 2, או הגדר אותה בתבנית ההשקה. השינוי חל על כל קונטיינר במופע. העדף תפקידי משימה של ECS כשהם זמינים, שקוראים אישורים מנקודת הקצה של אישורי הקונטיינר של ECS ונמנעים מהשינוי לגמרי, או החל את השינוי על מופע gateway ייעודי כדי להגביל את החשיפה.
יומן: אזהרה שמכילה upstream <name>: Google issued an access token that expires in <N>s, ב-upstream שקובץ האישורים של Google שלו הוא מסוג external_accountהבקשות מצליחות עד שאסימון הגישה הזה פג, ואז נכשלות אלא אם האסימון ש-credential_source מצביע אליו חודש קודם.אם תהליך כותב את האסימון הזה לקובץ, דאג שהוא יכתוב אחד חדש יותר מחמש דקות לפני שהישן פג
בעומס שיא, התגובות מתחילות לאט או נראות תקועות, או נכשלות עם 502 all upstreams failed בזמן שה-upstream תקיןלרפליקה יש יותר בקשות פתוחות ממה שהיא שולחת ל-upstream בבת אחת, ולכן הבקשות העודפות ממתינות בתוך ה-gateway. ב-upstream מסוג provider: anthropic, בקשה שממתינה יותר מ-timeouts.upstream_ttfb_ms מוותרת על ה-upstream הזה, וזה מייצר את ה-502 כשאף upstream מאוחר יותר לא מגיש אותה. היומן מציג אזהרה שמכילה client requests are open.הוסף רפליקות, או העלה את המגבלה בכל רפליקה. ראה Concurrent upstream requests.
ב-upstream שאינו provider: anthropic, תור עם השהיית חשיבה ארוכה נכשל. הפרוקסי לפני ה-gateway רושם בקשה אחת שנשארת פתוחה כ-12.5 דקות, ואז רצף של שגיאות 504Claude Code סיים זרם שכבר מסר את אירוע התגובה הראשון שלו ואחר כך נשא רק ping של keepalive. הוא שלח שוב את הבקשה בלי streaming, וכל תשובה נמשכת יותר מ-timeout של הפרוקסי.העלה את CLAUDE_STREAM_IDLE_TIMEOUT_MS עבור המפתחים שלך. ראה Long thinking ends in proxy timeouts.
תסמיןסיבהתיקון
על provider: anthropic, סבב עם הפסקת חשיבה ארוכה נכשל. הפרוקסי רושם בקשה אחת פתוחה במשך כ-20 דקות, ואז שגיאות 502 או 504Claude Code סיים זרם שכבר מסר את אירוע התגובה הראשון שלו ואחר כך נשא רק פינגים של keepalive. הוא שלח מחדש את הבקשה בלי סטרימינג, וכל תשובה נמשכת יותר מההמתנה של השער על ה-upstream, timeouts.upstream_ttfb_ms, או פסק הזמן של הפרוקסי.העלו את CLAUDE_STREAM_IDLE_TIMEOUT_MS עבור המפתחים שלכם. ראו חשיבה ארוכה ב-upstream של Anthropic API.
בקשות של מפתח נכשלות עם API Error: 400 you aren't in a group that can use this gateway. Ask your administrator to add you to oneלכל upstream יש רשימת groups, וההפעלה של המפתח לא נושאת אף אחת מהקבוצות שברשימה.הוסיפו את המפתח לקבוצה שברשימה ב-IdP שלכם, או רשמו upstream בלי groups אחרון כדי לשרת את כל השאר. השער קורא את הקבוצות שוב ברענון האסימון הבא של המפתח. אם ה-IdP השמיט קבוצות ונקודת הקצה userinfo שלו מחזירה אותן, הגדירו oidc.userinfo_fallback: true.
שגיאת IdP: unknown or unsupported scopeה-IdP דוחה scopes שהוא לא מזהההגדירו את oidc.scopes בדיוק לרשימה שה-IdP שלכם מקבל. היא חייבת לכלול openid. ברירת המחדל היא openid profile email offline_access.
הפעלות לא מתחדשות בשקט אחרי הגדרת oidc.scopesoffline_access הוסר מהדריסההוסיפו בחזרה את offline_access אם ה-IdP שלכם תומך בו. בלי אסימון רענון, מפתחים מריצים מחדש את כניסת הדפדפן בכל session.ttl_hours.
הדפדפן מציג "This request came from another site and was blocked"POST של טופס חוצה אתרים, שנחסם כהגנת CSRF. צפוי עבור דפים מוטמעים או דפים שעוברים דרך פרוקסיפתחו את קישור האימות ישירות
Chrome חוסם את לחצן Approve עם "Refused to send form data … violates … Content Security Policy directive: form-action", אבל אותו דף עובד ב-Safari או ב-FirefoxChrome אוכף את form-action על כל שרשרת ההפניות. ה-IdP שלכם מפנה הלאה למארח שני שאינו ברשימת ההיתר.הוסיפו כל origin נוסף בשרשרת ההפניות אל oidc.form_action_origins. פתחו Chrome DevTools → Console בדף Approve כדי לראות איזה origin נחסם.
הכניסה מסתיימת ב-IdP אבל ה-callback נכשל, עם שגיאת CSP ב-Chrome או "this sign-in link has expired" ב-Safariה-IdP החזיר את הקוד דרך response_mode=form_post, שמגיש אותו אוטומטית חוצה מקור באמצעות POST אל /oauth/callback. Chrome חוסם את זה תחת CSP מחמיר. Safari מאפשר את ההגשה אבל ה-callback קורא רק את מחרוזת השאילתה.ודאו שה-IdP שלכם מכבד את response_mode=query, שהשער מבקש במפורש כדי שה-callback יהיה הפניה פשוטה
הכניסה עובדת מקומית אבל נכשלת מאחורי ALBpublic_url עדיין מציין את ה-origin המקומי או הפנימי http://, ולכן ה-IdP מקבל redirect_uri שגויהגדירו את listen.public_url ל-origin החיצוני https:// ורשמו את <public_url>/oauth/callback אצל ה-IdP
מפתח רואה את בקשת האמון שוב ושובאישור TLS מתחלף לפי רפליקה או לפי בקשההשתמשו באישור יציב ב-ingress, או סיימו TLS פעם אחת והריצו רפליקות מעל HTTP רגיל באופן פנימי
CLI /login: "Could not verify the gateway's TLS certificate" או SELF_SIGNED_CERT_IN_CHAINשרשרת ה-TLS של השער חתומה על ידי CA פרטי שאינו במאגר האמון של מארח ה-CLIClaude Code קורא את מאגר האמון של מערכת ההפעלה כברירת מחדל בבינארי הנייטיב וב-Node 22.15 או חדש יותר. CLAUDE_CODE_CERT_STORE שולט בהתנהגות הזו. אם ה-CA מותקן במאגר האמון של מערכת ההפעלה, ודאו שהמפתחים על סביבת ריצה עדכנית. אחרת הגדירו את NODE_EXTRA_CA_CERTS לקובץ ה-PEM של אישור ה-CA לפני ההפעלה. בקשת טביעת האצבע של החיבור הראשון עדיין חלה.
CLI /login משלים את כניסת הדפדפן, ואז ההפעלה מסתיימת עם Cloud gateway sign-in was not completed ואי התאמה של אישור TLSבבקשה הראשונה אחרי הכניסה, השער הציג אישור שלא תואם את טביעת האצבע ש-Claude Code הצמיד, ולכן Claude Code לא שמר אישור גישה לשער. הסיבות הרגילות הן רפליקות מאחורי כתובת אחת שמגישות אישורים שונים, או משהו בנתיב הרשת שמיירט TLS.הגישו אישור אחד עבור שם המארח, למשל על ידי סיום TLS פעם אחת ב-ingress, ואז בקשו מהמפתח להריץ /login שוב. אם האישור הזה שונה מהאישור שהוצמד, Claude Code מציג שוב את בקשת האמון עם אזהרה שהאישור השתנה.
CLI /login נעצר עם The gateway's TLS certificate changed during sign-in: it no longer matches the one you trustedבקשת כניסה הגיעה לשרת שהאישור שלו לא תואם את האישור שהמפתח קיבל כש-/login התחיל: רפליקות מאחורי כתובת אחת שמגישות אישורים שונים, יירוט TLS בנתיב, או החלפת אישור בזמן שהכניסה הייתה בעיצומה.הגישו אישור אחד עבור שם המארח, ואז בקשו מהמפתח להתחיל את הכניסה שוב ולבדוק את האישור החדש בבקשת האמון.

ההודעה Cloud gateway sign-in was not completed מציינת את שם המארח של השער. כשל-Claude Code יש גם את טביעת האצבע שהוצמדה וגם את זו שהוצגה, ההודעה מציגה גם את 16 התווים הראשונים של כל אחת.

אם Claude Code מדווח couldn't load your organization's managed settings אחרי כניסה לשער, Claude Code מציין את הסיבה, מופעל מחדש במקום, וממשיך את השיחה. אם Claude Code לא יכול להתחיל מחדש, למשל בהפעלה ברקע, Claude Code מסיים את ההפעלה ושומר את הכניסה.

#כותרות בקשה גדולות מדי אחרי כניסה

בקשות של מפתח יכולות להיכשל עם שגיאת 431 אחרי כניסה כשהמפתח שייך לקבוצות IdP רבות.

השער עונה 431 כשהכותרות של בקשה מסתכמות ביותר מ-256 KiB, או ביותר מ-limits.max_request_header_bytes אם הגדרתם אותו. הוא לא כותב שורת לוג או אירוע ביקורת עבור הבקשות האלה. גרסאות שער לפני v2.1.284 עונות 431 מעל 16 KiB.

התחילו בראשון מאלה שחל על השער שלכם:

  • שער ישן יותר מ-v2.1.284: שדרגו את השער
  • limits.max_request_header_bytes מוגדר: העלו את הערך או הסירו את המפתח
  • אף אחד מהם לא חל, או 431 נמשך אחר כך: בקשו מה-IdP שלכם לפלוט פחות קבוצות. הגדרת ספק זהות מכסה איך Okta, Microsoft Entra ID ו-Google Workspace מספקים קבוצות

כשאתם מצמצמים את ה-claim של הקבוצות, שמרו את הקבוצות שציינתם בהגדרות האלה, שקובעות את הגישה, המדיניות, ה-upstreams ומגבלות ההוצאה של מפתח:

  • oidc.allowed_groups: קובע מי יכול להיכנס
  • admin.admin_groups: קובע מי יכול לקרוא ל-API של הניהול עם הפעלת השער שלו
  • match.groups ב-managed.policies: קובע איזו מדיניות חלה על מפתח
  • groups על upstream: קובע אילו upstreams משרתים מפתח
  • מגבלות הוצאה rbac_group: קובעות אילו מגבלות קבוצה חלות על מפתח

#חשיבה ארוכה מסתיימת בפסקי זמן של פרוקסי

אם ה-upstream שלכם הוא provider: anthropic, השתמשו בחשיבה ארוכה ב-upstream של Anthropic API במקום: גם שם אתם מעלים את CLAUDE_STREAM_IDLE_TIMEOUT_MS, אבל הזמנים והשגיאות שונים.

אם סבבים נכשלים אחרי חשיבה ארוכה והפרוקסי שלכם רושם בקשה אחת פתוחה במשך כ-12.5 דקות, ואז רצף של שגיאות 504, העלו את CLAUDE_STREAM_IDLE_TIMEOUT_MS במדיניות שער. לדוגמה, עם פסק זמן סרק של 240 שניות בפרוקסי, הרצף הוא 10 בקשות, כל אחת נחתכת ב-240 שניות.

  • הבקשה הראשונה: זרם שמוסר את אירוע התגובה הראשון שלו, message_start, ואחר כך רק פינגים בזמן ש-Claude חושב. עם הגדרות ברירת מחדל, Claude Code מסיים את הזרם הזה אחרי כ-12.5 דקות.
  • 10 האחרות: אותה בקשה, שנשלחת בלי סטרימינג ואחר כך מנוסה שוב, 10 שליחות בסך הכל כברירת מחדל. הן לא מקבלות פינגים, ולכן תשובה איטית פוגעת בפסק הזמן של הפרוקסי.

אין צורך בפסק זמן ארוך יותר של הפרוקסי עבור התיקון הזה. אם תעלו רק את פסק הזמן של הפרוקסי, בקשות בלי סטרימינג עדיין נכשלות ברגע שתשובה נמשכת יותר מההמתנה של Claude Code עצמו, 300 שניות כברירת מחדל.

#אישור הסיבה

בקשו ממפתח לשחזר את הכשל עם claude --debug-file ./claude-debug.txt, ואז חפשו בקובץ הזה את השורה הזו:

Error streaming, falling back to non-streaming mode: Stream idle timeout - no chunks received

אם המפתחים שלכם כבר הגדירו את CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK ל-1, אתם לא רואים בקשות בלי סטרימינג, והסבב מסתיים עם API Error: Stream idle timeout - no chunks received. אותו תיקון חל.

#בחירת ערך

בחרו ערך CLAUDE_STREAM_IDLE_TIMEOUT_MS שהעמודה השנייה שלו מכסה את הפסקת החשיבה הארוכה ביותר שלכם, או התחילו ב-1800000 אם אינכם יודעים אותה. זרם יכול להישאר על פינגים בלבד במשך כ-7.5 דקות יותר מהערך:

CLAUDE_STREAM_IDLE_TIMEOUT_MSזרם יכול להישאר על פינגים בלבד במשך
300000, ברירת המחדלכ-12.5 דקות
900000כ-22.5 דקות
1800000כ-37.5 דקות

אם upstream נתקע בזמן שהשער ממשיך לשלוח פינגים, המפתחים שלכם גם ממתינים פרק זמן כזה לפני ש-Claude Code מוותר על הזרם. חיבור ששותק לגמרי עדיין מסתיים אחרי 5 עד 6 דקות, כי פסק זמן הסרק של הגוף לא עוקב אחרי המשתנה הזה.

#מסירת הערך במדיניות

הוסיפו את רשומת ה-env לכל מדיניות ב-gateway.yaml שכבר מוסרת הגדרות Claude Code למפתחים שאתם רוצים לכסות. שימו אותה תחת מפתח code, cli או settings שכבר יש למדיניות. כדי לנסות את הערך תחילה, התחילו במדיניות שתואמת קבוצה אחת. ראו managed לאופן שבו מדיניות תואמת ויורשת. הדוגמה הזו מוסיפה את הרשומה למדיניות match: {} שהמפתח שלה הוא cli:

managed:
  policies:
    - match: {}
      cli:
        env:
          CLAUDE_STREAM_IDLE_TIMEOUT_MS: "1800000"

עם מפתח cli, אתם מכסים הפעלות מסוף, תוסף IDE ו-Agent SDK. עבור לשונית Code של Claude Desktop, ראו בחרו cli או code.

הפעילו מחדש את השער כדי שיקרא את הקובץ שנערך. אחר כך בקשו מהמפתחים להפעיל מחדש את Claude Code כדי לקבל את CLAUDE_STREAM_IDLE_TIMEOUT_MS.

#חשיבה ארוכה ב-upstream של Anthropic API

אם provider: anthropic הוא ה-upstream היחיד של המודל והפרוקסי שלכם רושם בקשה אחת פתוחה במשך כ-20 דקות, ואז שגיאות 502 או 504, העלו את CLAUDE_STREAM_IDLE_TIMEOUT_MS במדיניות שער.

  • הבקשה הארוכה: זרם שמוסר את message_start ואחר כך רק פינגים בזמן ש-Claude חושב. Claude Code מסיים אותו אחרי כ-20 דקות עם הגדרות ברירת מחדל, ומאוחר יותר אחרי שאתם מעלים את המשתנה.
  • השגיאות: בקשות ש-Claude Code שולח אחר כך בלי סטרימינג. כל אחת נכשלת עם 502 מהשער, או עם 504 של הפרוקסי שלכם אם פסק הזמן של הפרוקסי קצר יותר מההמתנה של השער. ההמתנה הזו היא timeouts.upstream_ttfb_ms, שאין צורך להעלות עבור התיקון הזה.

כדי לאשר את הסיבה, ראו אישור הסיבה.

בחרו את הערך שהזמן שלו מכסה את הפסקת החשיבה הארוכה ביותר שלכם: כ-20 דקות בברירת המחדל, 30 ב-900000, ו-45 ב-1800000. אחר כך עקבו אחרי מסירת הערך במדיניות.

#קשור