macOS 上 Clash 系統代理無效:分別排查瀏覽器與終端機

Safari、Chrome 會使用系統代理,終端機則不會自動套用。本文分兩路排查:先檢查網路設定中的代理欄位,再為 shell 設定 http_proxy 環境變數。

先釐清系統代理、終端機代理與 TUN 的差異

Clash 用戶端顯示「系統代理已啟用」,表示用戶端嘗試將代理設定寫入 macOS,不代表所有應用程式的流量都已接管。Safari 通常會使用系統代理;Chrome 預設也會讀取系統代理,但擴充功能、啟動參數或組織政策可能改變其行為。終端機中的命令列程式則各有代理設定方式,不能只憑瀏覽器能否開啟網頁來判斷。

圖形化用戶端負責匯入設定、切換策略組及管理系統設定;核心負責監聽代理連接埠、比對規則並轉送請求。即使用戶端介面仍在執行,核心也可能因設定錯誤而未能成功啟動。排查時應分開確認「代理設定已寫入」與「本機連接埠確實可用」。

連線方式主要檢查位置適用範圍
系統代理macOS 目前網路服務的代理欄位應用程式必須主動遵循這些設定
終端機明確指定代理命令參數、環境變數、工具設定通常只影響指定程序及其子程序
TUN 模式虛擬網卡、路由、DNS 與權限須有用戶端與核心支援,屬於另一種連線方式

確認核心正在執行,且本機連接埠有在監聽

查看執行設定,不要只看訂閱檔

先在用戶端確認目前設定是否成功載入,以及 HTTP、SOCKS 或混合連接埠的實際數值。不同用戶端的介面名稱與覆寫方式不盡相同,無法套用同一套選單路徑。訂閱檔中的連接埠也可能被用戶端設定覆寫,因此應優先查看執行設定與啟動記錄。

支援混合連接埠的核心可用同一連接埠接收 HTTP 與 SOCKS 請求。以下僅為部分欄位範例,並非包含節點與策略組的完整訂閱內容,排查時也不必覆寫原始檔案:

mixed-port: 7890
allow-lan: false
mode: rule

allow-lan: false 不影響本機使用 127.0.0.1。只排查目前這台 Mac 時,不必為了讓系統代理生效而開放區域網路存取。若要檢查 TCP 監聽狀態,可執行:

lsof -nP -iTCP:7890 -sTCP:LISTEN
  • 若有監聽記錄:確認程序是否屬於預期的用戶端或其核心,並確認監聽位址允許本機回環連線。
  • 若沒有記錄:檢查連接埠是否記錯、核心是否啟動失敗,以及設定記錄中是否有解析錯誤。必要時再以管理員權限確認程序是否可見。
  • 若連接埠被其他程式占用:先排除衝突,再同步修改用戶端的監聽連接埠與系統代理連接埠,不要只改其中一處。

略過系統設定,直接測試代理連線

curl -I -v --connect-timeout 10 --max-time 20 \
  --noproxy "" \
  --proxy http://127.0.0.1:7890 \
  https://example.com/

此命令會透過明確指定的 HTTP 代理存取 HTTPS 網址;--noproxy "" 可排除目前略過清單的影響。example.com 只是連線測試目標,也應換成實際出問題的網站重新測試。回應狀態碼不一定要是 200,重點是區分本機連線失敗、代理通道失敗、TLS 錯誤與遠端 HTTP 回應。

若顯示無法連線至 127.0.0.1:7890,先修復本機監聽;若已連上本機代理但逾時,再查看用戶端連線記錄、規則比對結果與節點記錄。明確指定代理後能正常存取,但瀏覽器仍失敗時,再進一步檢查 macOS 寫入代理設定的流程。

瀏覽器無法使用代理:檢查目前網路服務的代理欄位

確認目前使用的 Wi-Fi 或乙太網路服務

使用「系統設定」介面的 macOS,請前往「系統設定」→「網路」→目前使用的網路服務→「詳細資訊」→「代理」。Wi-Fi 也可以從「系統設定」→「Wi-Fi」→目前網路的「詳細資訊」進入。舊版「系統偏好設定」通常位於「網路」→目前服務→「進階」→「代理」。請以這台 Mac 上顯示的介面為準。

檢查「網頁代理(HTTP)」與「安全網頁代理(HTTPS)」:伺服器應指向 127.0.0.1,連接埠則應與用戶端的 HTTP 或混合連接埠一致。這裡的 HTTPS 代理設定是供 HTTPS 目標請求使用,不表示本機代理位址必須寫成 https://127.0.0.1。

macOS 會依網路服務分別儲存代理設定。剛從 Wi-Fi 切換到 USB 乙太網路時,舊服務上的設定正確,不代表新服務也設定正確。先列出服務,再查詢目前使用的服務:

networksetup -listallnetworkservices
networksetup -getwebproxy "Wi-Fi"
networksetup -getsecurewebproxy "Wi-Fi"
networksetup -getproxybypassdomains "Wi-Fi"
networksetup -getautoproxyurl "Wi-Fi"
networksetup -getproxyautodiscovery "Wi-Fi"

如果服務名稱不是 Wi-Fi,請以第一個命令列出的實際名稱取代,並保留引號。以下僅為預期欄位範例,並非這台 Mac 的檢測結果;HTTP 與 HTTPS 兩項都應分別檢查:

Enabled: Yes
Server: 127.0.0.1
Port: 7890
Authenticated Proxy Enabled: 0

排除 PAC、略過清單與瀏覽器設定覆寫

  • 自動代理設定:PAC 指令碼可依目標決定使用代理或直接連線。記下原始值後,暫時只保留正在驗證的一種代理方式,避免將 PAC 的分流結果誤判為手動代理失效。
  • 略過清單:localhost、127.0.0.1、*.local 常用於本機存取。檢查是否誤加目標網域或過於寬泛的萬用字元規則,不必清除所有本機略過項目。
  • 瀏覽器擴充功能:在 Chrome 中停用代理切換擴充功能後重新測試;若裝置受組織管理,也要檢查相關政策,不要直接覆寫受管理的設定。
  • 多個用戶端:避免同時讓兩個代理工具寫入系統設定。若設定反覆跳回舊連接埠,先確認是哪個程序仍在接管。

修改後重新載入網頁,必要時完全結束並重新開啟瀏覽器。優先選擇先前未載入過的頁面,避免快取影響判斷。同時觀察用戶端的連線記錄:完全沒有新連線,通常表示應用程式未進入代理流程;若出現連線卻被規則導向 DIRECT,問題則在規則選擇。

瀏覽器正常、終端機失敗:設定 shell 代理變數

在終端機啟動的 curl、Git、套件管理工具並不會一律遵循 macOS 系統代理。有些工具會讀取環境變數,有些使用自己的設定,也有些使用系統網路 API。建議先針對單一命令暫時測試,再決定是否設定整個 shell。

先為單一命令指定代理

http_proxy=http://127.0.0.1:7890 \
https_proxy=http://127.0.0.1:7890 \
curl -I --connect-timeout 10 --max-time 20 https://example.com/

這裡的 https_proxy 仍使用 http://,因為它指的是本機 HTTP 代理入口。存取 HTTPS 網站時,工具通常會透過 HTTP CONNECT 建立通道。不要只因目標是 HTTPS,就把變數值改成 TLS 代理位址。

為目前的終端機工作階段匯出變數

export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export no_proxy="localhost,127.0.0.1,::1"

env | grep -iE '^(http|https|all|no)_proxy='
curl -I --connect-timeout 10 --max-time 20 https://example.com/

這些匯出設定只影響目前的 shell 及之後啟動的子程序,不會自動變更其他已開啟的終端機視窗,也不會套用到所有從 Dock 啟動的圖形化應用程式。不同工具對變數大小寫的支援方式各異;例如 curl 的 HTTP 代理變數使用小寫 http_proxy,不能只設定大寫 HTTP_PROXY。

若使用 SOCKS 入口,可以單獨測試以下命令。只有在連接埠確實支援 SOCKS 時才使用;本例中的混合連接埠同時支援兩種請求。socks5h 會將目標主機名稱交由代理端解析,有助於區分本機 DNS 解析問題與代理連線問題。

curl -I --noproxy "" \
  --proxy socks5h://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 20 \
  https://example.com/

永久設定前,先處理舊變數

確認暫時測試成功後,可將需要的 export 行加入互動式 zsh 的 ~/.zshrc,再開啟新視窗或執行 source ~/.zshrc。其他 shell 請使用相應的啟動檔。關閉用戶端後,這些變數仍會指向本機連接埠,因此視需要啟用,通常更容易排查。

# 取消目前 shell 常見的代理變數
unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY

如果變數已寫入啟動檔,也必須刪除或註解相應行,否則新視窗會再次載入。檢查 all_proxy 是否指向舊連接埠,以及 no_proxy 是否包含目標網域;不同程式的優先順序與比對語法可能不同,不宜同時堆疊多組代理變數。

只有 Git 或套件管理工具失敗:檢查工具本身的設定

若同一個終端機中的 curl 已能正常連線,但 Git 仍失敗,接著應查看 Git 的設定來源,而不是反覆切換系統代理。舊的全域代理、儲存庫區域代理或依 URL 設定的代理,都可能讓 Git 使用不同的連線路徑。

git config --show-origin --get-regexp '.*proxy.*'

# 僅為本次 HTTPS 儲存庫連線指定代理
git -c http.proxy=http://127.0.0.1:7890 \
  ls-remote https://github.com/git/git.git HEAD

第二個命令是公開儲存庫的連線測試,不會修改全域設定。若查詢結果包含帳號、密碼或私人位址,分享記錄前請先遮蔽敏感資訊。只有確認全域 http.proxy 設定有誤時,才使用 git config --global --unset http.proxy;儲存庫區域與 URL 專用設定則應在各自的設定範圍內處理。

  • 使用 HTTPS 網址的 Git 請求與 git@主機:儲存庫 格式的 SSH 請求,使用的是兩種不同的通訊協定入口,不能以 HTTP 代理測試結果直接推斷 SSH 是否可用。
  • npm 可透過 npm config get proxy 和 npm config get https-proxy 檢查個別設定,修改前請先記下原始值。
  • 使用 sudo 後,環境變數可能會被清除。不要為了傳遞代理設定就直接保留所有環境變數,應確認該工具實際需要的最少設定。

請求已進入 Clash:檢查規則、DNS 與 TUN

連線記錄中出現目標請求,表示至少這筆請求已抵達核心。此時「系統代理無效」往往不是精確描述,應進一步查看比對到的規則、策略組目前的選擇,以及最終出口。規則模式通常依設定順序比對,末尾的 MATCH 只會處理前面未比對到的請求;選取某個策略組,也不代表該組目前的成員就是代理節點。

  1. 規則出口:記下目標網域比對到的規則,以及最後使用的是節點、DIRECT 還是 REJECT。若設定了直連規則,請求經過核心後仍可能直接連線。
  2. 節點與線路:針對同一個目標,換用其他可用節點重新測試。用戶端內的延遲測試只反映測試位址的結果,不能取代目標網站的實際連線測試。
  3. DNS:區分本機解析失敗、核心上游解析失敗與遠端連線失敗。不要把啟用 fake-ip 當成通用解法;這也會涉及 DNS 接管與應用程式相容性。
  4. TUN:只有確實需要接管不遵循明確代理設定的應用程式時,才檢查用戶端支援、權限、路由與 DNS 設定。基於 mihomo 的用戶端也可能提供不同的 TUN 控制選項,請勿混用其他用戶端的操作步驟。

重新測試順序與結束後的還原

完成調整後,依照以下順序驗證。瀏覽器與終端機都測試成功,才能確認兩種連線方式設定正確;只要能開啟單一網頁,並不能證明所有應用程式都會透過代理。

  1. 使用 lsof 確認實際連接埠正在監聽。
  2. 使用 curl --proxy 明確指定代理進行測試,確認本機入口與目標網站都能連線。
  3. 檢查目前網路服務的 HTTP 與 HTTPS 欄位,再於瀏覽器重新載入目標頁面。
  4. 檢查終端機變數與工具本身的代理設定,並在同一個終端機中分別測試 curl 和實際使用的命令。
  5. 結束用戶端前,先關閉由其接管的系統代理;結束後再次檢查網路設定,避免代理仍指向已停止監聽的連接埠。

若用戶端異常結束後所有網頁都無法存取,請前往目前網路服務的「代理」頁面,記下並關閉殘留的本機手動代理,接著取消終端機變數,再測試直接連線。受組織管理的代理與 PAC 設定應依管理要求還原,不要一併刪除。若仍需定位問題,整理實際連接埠、服務名稱、明確代理測試失敗的階段,以及已遮蔽敏感資訊的連線記錄,會比只描述「代理沒反應」更有幫助。

連接埠與規則欄位可參閱 YAML 手冊;設定匯入與 TUN 的平台操作可參考 使用教學。排查的核心始終是將應用程式入口、本機核心與遠端出口分段檢查。

下載 Clash