為什麼開了 Clash,終端機仍像「直連」?
在 macOS 上,多數 Clash 圖形用戶端都會提供系統代理(System Proxy)或類似開關。打開它之後,願意讀取 macOS 系統代理設定的應用程式(例如 Safari、部分依系統堆疊的元件)會被導向本機監聽埠,常見如 127.0.0.1:7890。
但終端機裡的 zsh/bash、以及 git、curl、Homebrew 這類工具,預設並不會因為「系統代理已開」就自動走代理。它們多半遵循另一套約定:Unix 世界裡約定俗成的環境變數,例如 http_proxy、https_proxy、all_proxy(以及大小寫變體)。因此你會看到一種非常典型的割裂:瀏覽器看起來正常,終端機卻仍連到本地電信或公司網路的出口。
先把期待校準:本文要做的不是「證明 Clash 壞掉」,而是把系統代理與Shell 代理環境變數兩條路分開,並給你可重現的匯出與驗證步驟。若你希望先建立整體架構認知,可先瀏覽站內的說明文件總覽,再回到本文操作。
系統代理與 http_proxy:兩套機制,不要混成一個開關
你可以用一句話記住:系統代理是寫進 macOS 網路偏好或代理資料庫的設定;而 http_proxy 這類變數是目前這個 Shell 行程繼承給子行程的「提示」。許多 CLI 工具會優先讀環境變數,有些則兩者都支援但優先順序不同,這就是為什麼「開了系統代理」不等於「同一個終端機視窗自動生效」。
實務上你會遇到三種情況:第一種是工具只認環境變數;第二種是工具兩邊都讀,但某個旗標讓它忽略其中一邊;第三種是工具自己另有代理設定(例如 git 的 http.proxy),覆寫了你在 Shell 裡匯出的值。接下來我們會先用「本機埠對齊 → 匯出變數 → 用 curl 驗證」把主線走通,再談 git 與 Homebrew 的細節。
第一步:從 Clash 用戶端確認本機 HTTP/混合埠
在設定任何環境變數之前,請先打開你的 Clash 用戶端,確認HTTP 埠或混合埠(mixed-port)實際數字。常見預設是 7890,但若你曾改過埠、或同時啟用多個服務,數字可能不同。請以用戶端介面顯示為準,不要硬抄教學文的數字。
接著在終端機用下列指令快速探測本機埠是否在聽(將埠號替換成你的設定):
lsof -nP -iTCP:7890 -sTCP:LISTEN
若沒有輸出,代表該埠沒有服務在聽:此時先回到用戶端確認核心是否啟動、埠是否啟用、是否被其他程式占用。若本機埠都連不上,後面談 http_proxy 也不會憑空生效。
第二步:在目前 Shell 匯出 http_proxy/https_proxy/all_proxy
以下假設你的 HTTP 代理位於 127.0.0.1:7890,且 Clash 提供 HTTP 與 SOCKS 兩種本機入口。若你的用戶端只開了其中一種,請把協定與埠改成介面顯示的組合。
在 zsh(macOS 預設)中,你可以先暫時匯出(僅影響目前這個終端機視窗):
export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
許多工具也會讀 all_proxy 作為「預設代理」的後備。若你的用戶端 SOCKS 埠是 7891(僅為示例,請替換成真實埠),可以一併設定:
export all_proxy="socks5://127.0.0.1:7891"
export ALL_PROXY="$all_proxy"
這裡有兩個實務習慣:第一,同時設定大寫與小寫變數,因為不同程式讀取的慣例不一致;第二,盡量用 127.0.0.1 而不是 localhost,避免少數解析行為在 IPv4/IPv6 之間搖擺,造成看似「偶發連不上本機代理」的假象。
第三步:用 curl 做最小可重現驗證
匯出後,請不要急著跑 brew update,先用 curl 驗證「終端機確實把流量交給本機代理」。下面這個做法能幫你分辨「代理沒吃到」與「代理有吃到但節點/規則有問題」:
curl -I https://www.google.com --max-time 15
若你同時想確認環境變數是否真的存在,可用:
env | grep -i proxy
當你看到 HTTP 200 或合理的回應標頭,且延遲符合預期,代表「Shell → 本機代理」這條鏈路至少已接通。若此時瀏覽器正常、但 curl 仍失敗,請優先懷疑:變數沒匯出到同一個 Shell、埠填錯、或用戶端規則把目標網域判成直連而與你想像不同——這就進入規則與策略組範疇,可延伸閱讀站內的規則分流教學。
git 與 Homebrew:除了環境變數,還有哪些坑?
Git 在大多數情境會遵循 http_proxy/https_proxy,但你也可能曾設定過 git config --global http.proxy。建議你用下列指令檢查是否另有全域設定:
git config --global --get http.proxy
git config --global --get https.proxy
若這裡有值,它可能與你剛匯出的環境變數不一致,導致你以為「Shell 已設好代理」,但 git 仍走另一條路。處理方式很務實:要么讓兩邊對齊,要么在確認不再需要時清除舊值,避免長期留下難以追蹤的設定。
Homebrew 在更新公式與下載資源時,通常會使用系統的 HTTP 堆疊與環境變數;實務上最常見的問題反而是:你只在某一個終端機視窗匯出變數,但另一個視窗執行 brew;或是 CI/IDE 內建終端機沒有讀到你的 .zshrc。先把「同一個視窗內 env | grep -i proxy 有值」當成硬門檻,再跑 brew update,會省下大量猜測時間。
127.0.0.1 埠即可。
NO_PROXY:避免本機與內網流量被誤送進代理
當你開始廣泛設定 http_proxy,另一個常見副作用是:連到本機服務或公司內網的請求也被送去代理,導致開發伺服器、私有 registry、或內部 API「突然連不上」。這時請補上 NO_PROXY(或 no_proxy),把不需要走代理的位址排除。
一個常見的起手式如下(請依你的內網網段調整):
export NO_PROXY="localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
export no_proxy="$NO_PROXY"
它的意義很單純:讓「明確應該直連」的目的地不要繞進 Clash,減少除錯時的變因。若你發現只有某些網域需要排除,也可以把網域列進去,但請注意不同工具對 NO_PROXY 的語法支援程度不完全相同。
要不要寫進 ~/.zshrc?先想清楚「永遠走代理」是不是你要的
把匯出指令寫進 ~/.zshrc 很省事,但它等同於讓多數終端機工作階段預設永遠嘗試走代理。若你只在特定網路環境需要代理,建議改用「需要時手動匯出」或獨立腳本(例如 source ~/proxy-on.sh),避免在公司內網、熱點、或離線除錯時被全域代理干擾。
另一個實務做法是:讓用戶端提供「一鍵複製終端機指令」或「匯出環境變數」功能(若你的 Clash 分支有內建),再貼到 Shell。重點仍是:埠號與協定必須與當前用戶端一致,複製後也要隨版本更新重新核對。
什麼時候該改走 TUN,而不是一直堆環境變數?
若你的目標是「讓不讀 http_proxy 的程式也進同一套路由與規則」,或你厭倦了每個工具各自一套設定,與其在 Shell 裡無限補洞,不如評估TUN 模式:它在更接近系統堆疊的位置接管流量,對「CLI 是否支援環境變數」依賴較低。站內的TUN 模式詳解已整理原理與常見斷線原因,可搭配閱讀。
但 TUN 需要驅動與較高權限,錯誤的 DNS 或路由可能讓整台機器看起來像全斷線。比較穩健的路線是:先把「本機埠正確、環境變數可驗證、規則没有把目標誤判」這三件事確認完,再決定是否上 TUN。
安裝來源與更新:先把用戶端準備好,再談終端機
最後一個隱性因素,是用戶端版本過舊或核心與 macOS 版本不相容,導致本機埠行為異常,讓你以為「環境變數無效」。建議固定從可信入口取得安裝包並持續更新。你可以先從本站用戶端下載頁取得目前平台可用版本,再回到本文完成匯出與驗證。
結語:把「哪一層沒吃到代理」說清楚,問題就會收斂
Clash 在 macOS 上「瀏覽器正常、終端機直連」並不是少見的靈異現象,而是系統代理與Shell 環境變數兩條路徑本來就不同。把本機埠對齊、用 http_proxy/https_proxy/all_proxy 建立可重現的鏈路,再用 curl 與 env 驗證,你會發現大多數案例都能在幾分鐘內定位,而不是靠重開機或重裝碰運氣。
相較於到處複製來路不明的長指令,更重要的是選擇介面清楚、能把埠與模式說明白、並在出問題時容易還原預設的用戶端。當你把「可連線」當成底線、把「可驗證」當成習慣,長期使用代理工具的成本會明顯下降。→ 立即免費下載 Clash,開啟流暢上網新體驗