תיעוד 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.
פריסת ייצור עוקבת אחרי ארבעה צעדים לפי הסדר, והסעיפים למטה תואמים אותם. בשניים הראשונים מקבלים החלטות. השניים האחרונים הם חומר עזר לעיון אחרי שהשער רץ.
- הגדרת ספק הזהויות: רישום לקוח ה-OAuth ובדיקת ההערות לפי IdP עבור Okta, Entra ו-Google
- פריסת השער: בניית תמונת קונטיינר נעולה לגרסה והרצה שלה ב-Kubernetes, ב-Cloud Run, או בפלטפורמה שלכם. הסעיף הזה מכסה גם החלטות על עלות, עקיפה, כמה שערים ו-serverless
- הגדרת תפעול: לוגים, בדיקות תקינות, התנהגות בהשבתה, סבב סודות ושדרוגים. חומר עזר כשמגדירים ניטור ו-runbooks
- סקירת מצב האבטחה: לאן הנתונים זורמים, מודל האיומים ותשובות לתאימות. חומר עזר לסקירת אבטחה
אם כניסה או עלייה נכשלות בדרך, עברו ישר אל 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רק כשה-scopegroupsמבוקש ב-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, השער כותב SSEpingאחרי שזרם היה שקט בערך 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:
- הורידו את בניית Linux לארכיטקטורה של התמונה מהפצה נעולה לגרסה. ראו Install a specific version לכתובת ההורדה.
- אמתו אותו מול
manifest.jsonהחתום ב-GPG של ההפצה, כמתואר ב-Binary integrity and code signing. - העתיקו אותו אל הקשר הבנייה.
שקפו את ההפצה אל הרישום הפנימי אם הבניות לא יכולות להגיע למארח ההפצה, ונעלו את הגרסה שהצי רץ.
מעבר לבינארי, התמונה צריכה:
- תמונה מבוססת 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כאשר אף אחת מהכותרות לא הוצגה
- אירועי mint ו-refresh מוצלחים נושאים את
יומנים תפעוליים: שורות קריאות לאדם עם קידומת
[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
סובב את סוד החתימה בשלבים כדי שהפעלות קיימות יישארו תקפות:
- צור סוד חדש. הוסף אותו בתחילת מערך
session.jwt_secret. - גלגל את הפריסה. אסימונים חדשים נחתמים עם הסוד החדש. אסימונים ישנים עדיין מאומתים.
- אחרי
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 gateway | forceLoginMethod או 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 network | HTTPS_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 proxy | HTTPS_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_url | Postgres לא מוגדר. ה-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.load | oidc.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 דקות, ואז רצף של שגיאות 504 | Claude Code סיים זרם שכבר מסר את אירוע התגובה הראשון שלו ואחר כך נשא רק ping של keepalive. הוא שלח שוב את הבקשה בלי streaming, וכל תשובה נמשכת יותר מ-timeout של הפרוקסי. | העלה את CLAUDE_STREAM_IDLE_TIMEOUT_MS עבור המפתחים שלך. ראה Long thinking ends in proxy timeouts. |
| תסמין | סיבה | תיקון |
|---|---|---|
על provider: anthropic, סבב עם הפסקת חשיבה ארוכה נכשל. הפרוקסי רושם בקשה אחת פתוחה במשך כ-20 דקות, ואז שגיאות 502 או 504 | Claude 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.scopes | offline_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 או ב-Firefox | Chrome אוכף את 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 יהיה הפניה פשוטה |
| הכניסה עובדת מקומית אבל נכשלת מאחורי ALB | public_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 פרטי שאינו במאגר האמון של מארח ה-CLI | Claude 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. אחר כך עקבו אחרי מסירת הערך במדיניות.
#קשור
- סקירת שער יישומי Claude: התחלה מהירה וחיבור מפתחים
- מדריך הגדרות: כל אפשרות של
gateway.yaml