先把「系統代理」拆成兩條鏈路
「系統代理」這個詞容易讓人以為是一個統一開關,實際上作業系統層面的代理設定只對遵守系統代理設定的應用程式生效,而「遵守」這件事分成兩條完全獨立的鏈路:
- 瀏覽器鏈路:主流瀏覽器(Chrome、Edge、Firefox 等)在 Windows/macOS 上預設讀取系統的代理設定項,這條鏈路由作業系統的網路設定面板控制。
- 終端/命令列鏈路:終端裡的
curl、git、套件管理器等工具不認系統面板,它們認的是http_proxy、https_proxy這類環境變數,系統代理開關對它們完全不起作用。
這就是為什麼很多人反饋「Clash 開著但沒生效」——其實生效範圍本身就不涵蓋終端,而問題恰恰出在終端這條鏈路沒設定。反過來也有人抱怨終端能用、瀏覽器卻直連,這多半是系統代理設定項本身沒被正確寫入,或者被例外清單擋住了。
Clash 系客戶端啟動後本身只做兩件事:在本機監聽一個代理埠(HTTP/SOCKS/混合埠),按規則把流量分發到不同節點。至於系統裡的其他程式要不要把流量送到這個埠,取決於系統代理設定或環境變數是否正確設定——這一步是作業系統的職責,不是 Clash 核心的職責。
第一步:確認 Clash 真的在監聽
在懷疑系統代理設定或環境變數之前,先確認埠本身是通的,這一步能排掉一半的「假性無效」。
- 打開客戶端的連線/埠設定頁,記下目前的 HTTP 埠(常見預設值 7890)以及是否啟用了混合埠。
- 用命令列直接測試這個埠,不經過系統代理開關,單純驗證監聽是否存在:
能拿到 HTTP 回應標頭(哪怕是 301/302)代表埠本身沒問題,問題在系統代理這一層沒接上;如果直接顯示連線被拒,說明客戶端沒啟動或埠被改過,先解決這一步再往下看。curl -x http://127.0.0.1:7890 https://www.google.com -I - Windows 下可用
netstat -ano | findstr 7890、macOS/Linux 下用lsof -i :7890確認佔用該埠的程序確實是 Clash,而不是被別的程式搶占。
| 埠類型 | 常見預設值 | 典型用途 |
|---|---|---|
| HTTP 埠 | 7890 | 瀏覽器系統代理、大部分終端工具 |
| SOCKS 埠 | 7891 | 部分要求 SOCKS5 的客戶端 |
| 混合埠(mixed-port) | 視設定而定 | 同一埠同時接受 HTTP 與 SOCKS 請求 |
| 控制面板埠 | 9090 | RESTful API,與代理轉發無關 |
瀏覽器這條線:系統代理為什麼沒吃到
瀏覽器鏈路失效常見於三個環節,按順序檢查:
- 系統代理開關沒真正打開——客戶端裡的「設為系統代理」是個連動開關,有些版本重啟後不會自動恢復上次狀態,需要手動確認一次目前是否為開啟狀態,而不是憑印象判斷。
- 瀏覽器有自己的獨立代理設定——多數瀏覽器預設跟隨系統,但如果之前手動改過「手動設定代理」或安裝過代理管理類擴充功能,瀏覽器會優先讀取自己的設定而忽略系統層設定,這種情況下把瀏覽器代理模式改回「系統代理」或直接停用相關擴充功能。
- 企業/教育網路的群組原則覆寫——部分辦公電腦由群組原則統一管理網路設定,系統代理項即使顯示已勾選,實際瀏覽行為仍受原則層覆寫,這種環境下建議直接用 TUN 模式繞開系統代理這層設定(見文末)。
瀏覽器隱私/無痕視窗有時會單獨維護一套網路設定快取,一般視窗生效不代表隱私視窗同步生效,遇到「部分視窗能用部分不能用」先重開一次隱私視窗再判斷。
終端這條線:環境變數與 shell 設定
終端不讀系統代理面板,它認的是環境變數,最常用的幾個是 http_proxy、https_proxy、all_proxy(小寫規範,大寫形式各工具相容性不一)。臨時測試可以直接在目前終端會話裡匯出:
export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export all_proxy="socks5://127.0.0.1:7891"
這種寫法只對目前終端視窗生效,關閉視窗就失效。如果想讓每次開終端都自動生效,要把這幾行寫進 shell 的啟動設定檔——bash 使用者寫 ~/.bashrc 或 ~/.bash_profile,zsh 使用者(macOS 預設 shell)寫 ~/.zshrc,寫完執行 source ~/.zshrc 讓目前視窗立即讀取,不用重開終端。
常見的三個坑:
- 寫錯了設定檔——macOS 預設 shell 早已切換為 zsh,很多人還在照著舊教學改
.bashrc,結果新開的終端根本不會讀到。用echo $SHELL先確認目前用的是哪個 shell。 - 埠號與實際不一致——客戶端換過埠、重裝過設定檔後忘記同步更新環境變數裡寫死的埠號,這類問題只在終端出現,瀏覽器因為跟隨系統代理設定反而是正常的,兩邊表現不一致時先比對埠號。
- 某些工具單獨讀取自己的設定項——比如 Git 會優先讀取
git config --global http.proxy裡單獨設定的代理位址,即使環境變數對了,Git 仍按自己的設定項走,需要額外執行:git config --global http.proxy http://127.0.0.1:7890 git config --global https.proxy http://127.0.0.1:7890
設好環境變數後,用 curl -v https://ipinfo.io/ip 輸出的 IP 是否變成節點所在地區的 IP 來驗證,而不是只看命令是否報錯——沒有報錯不代表真的走了代理,有可能是直連也成功存取了。
PAC 殘留與代理例外名單
如果之前用過基於 PAC 檔案的代理工具(自動設定腳本模式),卸載或改用 Clash 之後,系統裡可能殘留著舊的 PAC 位址沒有清空,導致系統代理面板顯示的是「使用設定腳本」而不是手動指定的 IP+埠,這種殘留優先度往往比手動代理更高,表現就是開了系統代理卻依舊直連或存取異常。檢查方法:
- Windows:打開「設定 → 網路和網際網路 → 代理」,看「使用設定腳本」是否被啟用,如果是,先關掉再單獨開啟「手動設定代理」。
- macOS:系統設定 → 網路 → 對應網路服務的詳細資訊 → 代理伺服器,檢查「自動代理設定」是否勾選了舊的 PAC 位址,同時確認「網頁代理伺服器(HTTP)」和「安全網頁代理伺服器(HTTPS)」這兩項分別填的是 Clash 的埠。
另一個容易被忽略的地方是代理例外清單(no_proxy / bypass list)。系統代理設定裡通常有一欄「這些位址不使用代理伺服器」,預設會包含 localhost、127.* 等本機位址,這是正常的,但有些安裝包或舊設定會往這裡塞進大段通配規則,導致大量正常網站被劃進例外名單,存取時全部走直連而不經過代理。檢查時重點看這個例外欄是不是被寫入了超出預期的網域段,終端裡對應的環境變數是 no_proxy,同樣值得單獨檢查一遍:
echo $no_proxy
no_proxy 裡如果寫了 * 或者過寬的通配符(比如整個頂級網域),會讓終端代理形同虛設,所有請求都被判定為例外走直連,這種寫法建議直接清空重寫,只保留必要的本機位址。
排查順序清單與兜底方案
把上面的內容壓縮成一份可以照著走的順序表,遇到「系統代理開了卻沒生效」從上到下逐項核對:
- 用
curl -x直接測埠,確認 Clash 本身在監聽且埠號正確。 - 檢查客戶端的「設為系統代理」開關是否真的處於開啟狀態。
- 檢查瀏覽器是否被單獨設定過手動代理或裝了代理管理擴充功能,統一改回跟隨系統。
- 檢查系統代理面板是否殘留舊的 PAC 腳本位址,清空後手動指定 IP 與埠。
- 檢查系統代理例外名單與終端
no_proxy變數,清理過寬的通配規則。 - 終端環境變數按目前 shell(bash/zsh)寫入對應設定檔,埠號與客戶端實際設定保持一致。
- 單獨檢查 Git 等自帶代理設定項的工具,避免它們讀取了過期的舊位址。
如果排查完還是有個別應用程式死活不認系統代理設定或環境變數——這類情況並不少見,一些獨立行程的程式壓根不檢查系統代理面板,也不讀 shell 環境變數,只認自己寫死的直連邏輯。遇到這種「死不聽話」的應用程式,更省事的做法是切到 TUN 模式:客戶端在系統網路層建一張虛擬網卡,所有出網流量在網路層被統一接管,不再依賴某個應用程式是否主動「配合」系統代理設定,瀏覽器、終端、其他獨立行程的流量會被一併處理。TUN 模式的接管範圍更徹底,但對 DNS 處理、網卡權限的要求也更高,設定上比系統代理多一步授權,具體開啟方式可以在教學頁裡查看分平台的操作步驟。