憑證裝了它還是不認:Claude Code 在公司網路後面該設的那幾個變數
公司配的筆電,Claude Code 裝完,第一次打 claude 下去,第一個請求就死在憑證錯誤上。同一個版本在家裡那台機器跑得好好的。
你去問 IT,得到的回覆是公司有做 TLS 檢查,根憑證早就推到每一台機器了。
推是推了。它就是不認。
export 完沒生效,不是你設錯,是設得太晚
最直覺的動作是補 proxy。你開一個新分頁 export HTTPS_PROXY=http://proxy.example.com:8080,切回原本那個還開著的 session 再送一次,錯誤一模一樣。
這裡有一條規則寫在官方那頁的第一段,但你通常要撞過一次才會回頭去讀它:shell 裡 export 的環境變數,Claude Code 在啟動時讀一次。原文是「Variables exported in your shell are read once at startup, so a running session doesn’t pick up later changes to your shell environment」。一個跑起來的 session 不會回頭看你的 shell 後來變成什麼樣子。
所以第一條路的方向沒錯,錯的是時機。關掉重開,export 完再啟動,proxy 那一關就過了。
順帶一提,這批設定裡唯一會在啟動當下被檢查的就是 proxy URL。值 parse 不出來(典型是漏掉 http:// 這個 scheme),Claude Code 會直接讓啟動失敗,而且錯誤訊息會指名是哪一個變數。其他的都不驗,你要等到某個請求炸了才會知道。
憑證明明裝在系統裡,它就是讀不到
proxy 通了,憑證那關還是不過。
你打開鑰匙圈確認過一次,公司的根憑證確實在裡面,也確實標成信任。IT 沒騙你。
第二條死路藏在執行環境。Claude Code 預設同時信任兩份東西:它自己打包的那套 Mozilla CA,加上作業系統的信任庫。但讀作業系統那一份有前提,要 runtime 提供 tls.getCACertificates。原生安裝器裝的一定有;用 npm 裝的,需要 Node 22.15 或更新。低於那個版本,實際生效的只剩內建那套跟 NODE_EXTRA_CA_CERTS。
也就是說,憑證在不在系統裡從來不是重點。重點是你這個 runtime 讀不讀得到它。這種壞法特別討厭,因為每一個你想得到的檢查都會回報正常:憑證在、信任旗標對、路徑沒錯,然後連線照樣失敗。
站在那個畫面前要怎麼確診?先查一個數字,node -v。這一關只有 npm 裝的會卡,原生安裝器裝的不用查。真的想不起來自己當初是哪一種裝法也不必糾結:直接設 NODE_EXTRA_CA_CERTS,它在兩種情況下都生效,是這裡唯一不用先確診就能走的一條。
要嘛把 Node 升上去,要嘛別繞了,直接指:
1 | export NODE_EXTRA_CA_CERTS=/path/to/ca-cert.pem |
想更省事還有一把開關。CLAUDE_CODE_CERT_STORE 吃逗號分隔的清單,認得的值只有 bundled(內建的 Mozilla CA 集)跟 system(作業系統信任庫),預設是 bundled,system。要縮成只信任其中一邊就寫單一個值。它沒有自己的 settings.json schema key,只能走 env 區塊或直接放在 process 環境裡。
該搬家的其實是設定本身
到這裡為止都還在修症狀。真正該換的是這批設定住在哪裡。
它們全部可以寫進 settings.json 的 env 區塊,而那才是它們該待的地方:
1 | { |
NO_PROXY 空白分隔或逗號分隔都吃,* 代表整個繞過。小寫變體也認得,優先序是 https_proxy、HTTPS_PROXY、http_proxy、HTTP_PROXY,取第一個有值的。至於 loopback 上的 WebSocket 連線,Claude Code 本來就不會送進 proxy,localhost、::1、127.0.0.0/8 都不用特地寫進去。
兩件事先講清楚,免得你白設一輪。SOCKS proxy 不支援,文件寫得很乾脆。NTLM、Kerberos 這種需要進階認證的 proxy 也不在射程內,官方建議是改走支援該認證方式的 LLM gateway。
我的立場是:在公司網路後面,這些變數不該只活在 .zshrc 裡。如果你只是自己開互動式 session、從來不用背景 agent、也沒有人要照著你的步驟重現環境,那 export 一次確實就夠了,下面這段可以跳過。
背景 agent 是那條分水嶺。它不跑在派它出去的那個終端機裡,而是掛在一個 per-user 的 supervisor 底下,那個 process 會活得比你的 shell 久,而且全部終端機共用同一個。它繼承的是「第一個把它冷啟起來的那個 shell」的環境;如果 supervisor 是作業系統裝的服務,它根本收不到任何 shell 環境。
於是你會遇到那種最難查的症狀:同一台機器,同一組變數,有時候通有時候不通,取決於今天是哪個視窗先把 supervisor 叫起來的。
怎麼認出自己中的就是這一種?看失敗落在哪裡。你在終端機裡開互動式 session 一切正常,只有丟給背景 agent 的工作卡在憑證或 proxy 上,那就不是設定錯了,是設定沒走到那裡。同一組變數在兩條執行路徑上給出兩種結果,這件事本身就在講「環境是繼承來的」。
而且它不會自己好。supervisor 已經用錯的環境冷啟過一次,之後每一個背景 session 都吃那一份,你回頭改 .zshrc 它不會知道。再 export 一次是沒有用的,你得讓它重新起一次;或者一開始就別讓設定住在 shell 裡。
設定檔是唯一能穩定送達每一個背景 session 的路徑。
「有那一列」不等於「它載進去了」
設完之後怎麼知道生效了?這一段是整篇我最想講的。
第一條路是 debug log。claude --debug 啟動,但輸出不會印在終端機上,它落在 ~/.claude/debug/<session-id>.txt,也可以用 --debug-file <path> 指到別的地方。你要找的是這三行:
1 | CA certs: Appended extra certificates from NODE_EXTRA_CA_CERTS (/etc/ssl/certs/corp-ca.pem) |
讀不到檔案的話,對應位置會換成 Failed to read 或 Failed to load 開頭的那一行,後面帶原因。
第二條路是互動模式裡跑 /status。看起來更方便,但這裡藏了一個很值得記住的差別。
/status 的 mTLS client cert 跟 mTLS client key 這兩列,只在檔案真的載入成功時才會出現。缺一列,就是那一份沒載進去,去 debug log 找原因。這種列是好證據:有它就代表事情成了。
Additional CA cert(s) 那一列不一樣。它顯示的是 NODE_EXTRA_CA_CERTS 的路徑,而且不檢查那個檔案到底有沒有載起來。你打錯路徑,它照樣把那個錯的路徑印給你看。
同一個畫面,兩種列,證據強度天差地遠。一種是「載成功才會出現」,另一種是「你填了什麼就印什麼」。把後者當成前者來讀,你會得到一個看起來很有依據的錯誤結論——而錯誤結論裡最難自己抓的,就是這種有畫面可以指的。要確認 CA,只能回 debug log。
白名單到底要開幾個洞
防火牆那張表,官方列了十幾個 host。挑幾個真的會咬人的講:
| 網域 | 少了它會怎樣 |
|---|---|
api.anthropic.com |
API 請求、feature flag、WebFetch 的網域安全檢查全掛 |
claude.ai、platform.claude.com |
登入拿不到 token;OAuth 的交換、更新、撤銷都走 platform.claude.com |
registry.npmjs.org |
plugin 安裝、npx 起的 MCP server、npm/bun 版本的 Claude Code 自己 |
bridge.claudeusercontent.com |
Claude in Chrome 擴充的 WebSocket 橋接 |
*.frame.claudeusercontent.com |
Artifact 內容讀取 |
mcp-proxy.anthropic.com |
來自 claude.ai 的 MCP 連接器 |
表上另外那兩個 Datadog 的 intake host 只載營運遙測,可以用 DISABLE_TELEMETRY 之類的開關關掉,關掉就不必放行。
還有一個很容易漏的。你以為改走 LLM gateway、把 ANTHROPIC_BASE_URL 指出去之後,api.anthropic.com 就不需要了。fast mode 的可用性檢查還是打那個 host,不是打你的 gateway base URL。所以 proxy 的白名單裡那一條得留著。
換憑證那天會發生什麼事
mTLS 還有第三個變數 CLAUDE_CODE_CLIENT_KEY_PASSPHRASE,給加密過的私鑰用。真正值得單獨記一下的是輪替行為。
Claude Code 不監看這兩個檔案。你把檔案換掉的那一刻,它什麼都不會做。它會在兩種時機重讀:一是某次 API 請求撞到連線層的錯誤(連線被重設、TLS handshake 失敗)之後重試時,二是下一次套用設定的時候,哪個先到算哪個。v2.1.232 之前連第一種都沒有。
推論一下就會發現有個縫。如果你的 gateway 是把 handshake 完成、然後回一個 HTTP 錯誤,那不算連線層失敗,它不會重讀。這種情況下新憑證要等到下次套用設定或重啟才進得去。
還有一種是輪替寫到一半被讀到,憑證跟金鑰對不起來,它會沿用舊的那一對,下次失敗再讀。想整個關掉連線錯誤重讀的行為,有 CLAUDE_CODE_DISABLE_MTLS_RELOAD_ON_STALE_CONNECTION=1。
這篇的變數名、路徑與行為全部照 Claude Code 官方的 Enterprise network configuration 文件寫,是 2026 年 9 月的版本。我沒有一個裝了 TLS 檢查代理的企業環境可以驗,所以上面沒有任何一句是「我設完就通了」。網域那張表也會隨版本增減,照著開之前自己對一次原文。
回到那台筆電
現在同樣的畫面再來一次:第一個請求死在憑證錯誤。
我不會先去碰 shell。我會打開 ~/.claude/settings.json 的 env 區塊,把 proxy 跟 CA 路徑寫進去,然後 claude --debug 重啟一次,去 ~/.claude/debug/ 底下找那三行。三行都在,才算設定真的進去了;/status 那列 CA 路徑看起來再漂亮,都不算。
真正省時間的不是記住這幾個變數叫什麼,是先分清楚兩件事:設定住在哪裡(shell 還是設定檔),以及你手上那個證據能證明到哪一步。前者決定它會不會送達背景 agent,後者決定你是在除錯,還是在安慰自己。


































































































































































































