先用明確指定代理的請求定位問題,再調整系統代理或 DNS。用戶端顯示「已連線」,通常只代表核心或接管功能已啟動,不代表瀏覽器請求確實經過該核心,也不代表目前的節點能連上目標網站。請依「監聽連接埠 → 指定代理請求 → 應用程式代理 → DNS → 規則與節點 → TUN」的順序檢查,每次只調整一項。
1. 確認核心正在監聽,而不只是介面有開啟
先檢查程序與連接埠。以下兩個指令只會讀取狀態,不會修改設定。ss 顯示程序資訊可能需要管理員權限;若沒有權限,仍可先確認監聽位址與連接埠。
pgrep -af 'mihomo|clash'
sudo ss -lntp 'sport = :7890'
- 沒有監聽結果:檢查核心是否啟動失敗、設定檔是否解析錯誤,或實際使用的連接埠是否不是 7890。
- 監聽於
127.0.0.1:7890:本機程式可以連線,區域網路中的其他裝置無法直接使用此入口。 - 監聽於
0.0.0.0:7890:入口涵蓋 IPv4 本機網路介面,還須檢查區域網路存取權限與防火牆。 - 連接埠由其他程序占用:先確認是哪個程序,再停用衝突的執行個體,請勿直接批次結束所有代理程序。
mixed-port 可同時接受 HTTP 和 SOCKS 請求。若設定只使用 port 或 socks-port,就必須分別使用對應的協定與連接埠;external-controller 則是管理介面,不能當作瀏覽器代理連接埠。
# 僅檢查此目錄中的設定,不會啟動第二個常駐執行個體
mihomo -t -d "$HOME/.config/mihomo"
測試通過只代表目前的二進位檔能解析該設定,不保證服務實際使用這份設定。若是自建的 systemd 使用者服務,可執行以下指令確認啟動參數;系統層級服務則應改用 sudo systemctl,並移除 --user。
systemctl --user cat mihomo.service
systemctl --user status mihomo.service --no-pager
journalctl --user -u mihomo.service -b -n 80 --no-pager
若顯示找不到服務,請回到圖形用戶端查看核心記錄,不要為了排查而額外啟動另一個使用相同連接埠的服務。請優先搜尋 address already in use、設定解析失敗、權限不足及 Provider 載入錯誤。
2. 用 curl 明確指定代理,區分應用程式與核心問題
先測試 HTTP 代理入口。--noproxy "" 會清空這次請求的略過清單,避免環境變數中的 NO_PROXY 讓測試意外直接連線。範例使用相同的 HTTPS 位址,方便比較結果;實際排查時,也應對無法開啟的目標執行相同測試。
curl --noproxy "" -x http://127.0.0.1:7890 \
--connect-timeout 5 --max-time 20 \
-v -o /dev/null https://example.com/
| 結果 | 說明 | 下一步 |
|---|---|---|
Connection refused | 本機 TCP 連線遭拒 | 確認監聽連接埠與位址 |
407 | 代理要求驗證 | 確認設定中的驗證方式與應用程式憑證 |
| 已建立 CONNECT,之後逾時 | 代理入口已有回應,但後續連線尚未完成 | 檢查規則、節點與目標連線記錄 |
certificate verify failed | TLS 驗證失敗 | 檢查系統時間、憑證存放區與中間代理 |
| 收到目標 HTTP 回應 | 此請求路徑已可正常往返 | 檢查瀏覽器與系統代理設定 |
HTTP 403 或 429 代表目標網站或中間服務已回應,不應直接判定為連接埠失效。單次成功也只能證明目前目標與規則路徑可用,不能據此認定所有網站、UDP 或 IPv6 都正常。
再比較一次不使用明確代理的請求
curl --proxy "" --noproxy "*" \
--connect-timeout 5 --max-time 20 \
-I https://example.com/
此指令會停用 curl 的明確代理,但不會略過系統中的 TUN、策略路由或透明轉送。若要比較真正的直接連線基準,請先在可復原的本機環境中關閉 TUN,再重複測試。若明確指定代理後請求成功、瀏覽器卻失敗,請優先查看下一節,不要立刻更換 DNS。
3. 確認系統代理、瀏覽器設定與終端機環境變數一致
Linux 桌面代理、終端機環境變數與瀏覽器本身的設定是不同入口。啟用其中一項,不代表另外兩項也會自動生效。以 GNOME 桌面為例,前往「設定」→「網路」→「網路代理」,選擇「手動」,將 HTTP 與 HTTPS 的代理主機設為 127.0.0.1、連接埠設為 7890;不同發行版的選項名稱可能略有差異。
HTTPS 欄位代表「HTTPS 請求要使用哪個代理」,不表示代理協定必須設為 HTTPS。使用本機 mixed-port 時,終端機中的 https_proxy 通常仍應填入 http://127.0.0.1:7890。
# 查看目前 shell 中的代理變數;輸出可能含有憑證,請勿直接公開
env | grep -iE '^(http|https|all|no)_proxy='
# 僅為這次 curl 請求設定代理
http_proxy=http://127.0.0.1:7890 \
https_proxy=http://127.0.0.1:7890 \
curl --noproxy "" --max-time 20 -I https://example.com/
檢查略過清單與重複接管
NO_PROXY=*會讓支援此變數的程式略過代理。測試時請清空此變數,再逐一加回本機與內部網路例外。- 可在 Firefox 的「設定」→「一般」→「網路設定」→「設定」中確認使用的是系統代理還是手動代理。擴充套件也可能會接管這項設定。
- 舊的 shell、已啟動的 IDE 與背景服務不會自動取得新終端機中的變數。修改後,應在相關程序的環境中重新驗證。
- 容器中的
127.0.0.1指向容器本身,而不是主機。主機連接埠正常,不代表容器也能連線。
若懷疑舊變數造成干擾,可用以下指令進行一次乾淨的測試。這只會影響此次子程序,不會刪除 shell 設定檔中的持久設定。
env -u http_proxy -u https_proxy -u all_proxy -u no_proxy \
-u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY -u NO_PROXY \
curl --noproxy "" -x http://127.0.0.1:7890 \
--max-time 20 -I https://example.com/
4. 區分系統 DNS、核心 DNS 與 fake-ip
網域名稱解析失敗,不一定是系統 DNS 出問題。HTTP CONNECT 可以將目標主機名稱交給代理;SOCKS 則可透過選項選擇由哪一端解析。請用以下兩個指令比較:第一個由 curl 在本機解析,第二個則將網域名稱交由 SOCKS 代理解析。
curl --noproxy "" --socks5 127.0.0.1:7890 \
--max-time 20 -I https://example.com/
curl --noproxy "" --socks5-hostname 127.0.0.1:7890 \
--max-time 20 -I https://example.com/
若本機解析失敗、代理端解析成功,應優先檢查系統解析器;但這只是線索,並非唯一結論,因為兩次連線可能命中不同的位址與規則。請繼續查看系統實際使用的解析設定。
getent ahosts example.com
ls -l /etc/resolv.conf
cat /etc/resolv.conf
# 僅適用於已啟用 systemd-resolved 的系統
resolvectl status
resolvectl query example.com
若 /etc/resolv.conf 指向由 systemd-resolved 或 NetworkManager 管理的檔案,直接覆寫可能在重新連線後失效。請透過對應的網路管理工具修改 DNS,不要讓 DHCP 更新設定的同時又手動寫入。
檢查 mihomo 的 DNS 監聽與 fake-ip 路徑
假設實際執行的設定中已有 dns.listen: 127.0.0.1:1053,可在已安裝 dig 的終端機直接查詢核心 DNS。若監聽連接埠不同,也要相應調整指令。
dig @127.0.0.1 -p 1053 example.com A
dig @127.0.0.1 -p 1053 example.com AAAA
使用 enhanced-mode: fake-ip 時,網域名稱可能會解析為設定範圍內的合成位址,常見範圍為 198.18.0.1/16。這不是公開網際網路上的目標位址,後續連線必須回到保有網域對應資料的代理核心。若應用程式取得 fake-ip,卻透過未受接管的路由直接連線,就可能一直逾時。
上游 DNS 本身也可能需要網域解析或代理連線。請檢查 default-nameserver、nameserver、proxy-server-nameserver 的用途與目前設定,避免節點網域的解析依賴尚未建立的代理連線。欄位說明可參考設定參考;請勿一次更換所有上游 DNS,再猜測是哪一項生效。
5. 檢查規則命中與節點狀態,別只看延遲數字
在用戶端的連線記錄中找到測試網域,確認最終出站是 DIRECT、某個代理節點,還是拒絕動作。規則由上往下比對,最後的 MATCH 是預設規則;若前面的網域或 IP 規則已命中,修改預設策略組不會改變這次請求。
- 記下測試時間與目標網域,再重新執行一次明確指定代理的 curl 請求。
- 在連線記錄或日誌中搜尋對應網域,確認命中的規則與策略組。
- 檢查策略組目前選用的項目,尤其是巢狀策略組最後使用的實際節點。
- 暫時改選另一個已知可用的節點,保持目標位址、請求方式與模式不變,再比較結果。
延遲測試成功,只代表當時能連上設定中的測試 URL,不代表所有網站都能使用。節點可能只在特定目標、協定或位址族上失敗。訂閱更新成功也只代表已取得設定,不能證明節點的驗證資訊、流量額度與服務端口都正常。
短時間提高日誌層級,完成後恢復
必要時可將實際設定中的 log-level 暫時設為 debug,重現一次問題後再恢復為 info。圖形用戶端應透過提供的設定覆寫或日誌選項修改,避免產生的執行設定在下次更新時被覆蓋。分享日誌前,請移除訂閱網址、驗證資訊與私人存取網域。
# 自建使用者服務:修改設定後先測試,成功再重新啟動
mihomo -t -d "$HOME/.config/mihomo" && \
systemctl --user restart mihomo.service
journalctl --user -u mihomo.service --since "5 minutes ago" --no-pager
遇到憑證錯誤時,先執行 timedatectl status 檢查時間與同步狀態,再檢查憑證存放區與節點網域。請勿把停用憑證驗證當成一般修復方式,否則可能掩蓋位址錯誤或中間連線問題。
6. 明確指定代理正常但 TUN 失敗:檢查權限、路由與 IPv6
若 curl -x 正常,但啟用 TUN 後瀏覽器無法連線,且已有證據確認連接埠與節點可用,接下來應著重檢查透明接管。TUN 需要虛擬網卡、相應權限與路由;設定中的 tun.enable: true 不代表這些條件都已具備。
ls -l /dev/net/tun
ip -br link
ip rule show
ip route show table all
ip -6 route show table all
- 找不到
/dev/net/tun:檢查系統是否支援並已啟用 TUN。容器或受限的虛擬化環境還需要主機授權。 - 日誌顯示建立介面或修改路由失敗:請使用用戶端提供的服務模式,或確認自建服務的權限;請勿任意放寬執行檔權限。
- 若同時執行其他 VPN:比較雙方的策略路由、預設路由與 DNS 接管設定。測試時一次只保留一條接管路徑。
- IPv4 正常、IPv6 失敗:分別檢查 IPv6 預設路由、DNS 的 AAAA 回應,以及目前核心的 IPv6 處理設定。
# 關閉 TUN 後,比較主機原始 IPv4 / IPv6 連線能力
curl --proxy "" --noproxy "*" -4 --max-time 15 -I https://example.com/
curl --proxy "" --noproxy "*" -6 --max-time 15 -I https://example.com/
此處的 -4 與 -6 用來檢查直接連線的基準狀態。對本機 HTTP 代理使用相同選項,無法可靠控制遠端節點連線至目標時使用的位址族。若網路本身沒有 IPv6 出口,IPv6 測試失敗不代表節點故障。
7. 以最少變更恢復連線,並保留重現紀錄
排查完成後,請用相同目標重新測試終端機、瀏覽器與 TUN 這三條路徑。不要只憑系統匣圖示或單次測速判斷問題已解決。建議保留下列紀錄,方便問題再次發生時直接比較。
- 執行中的執行個體:記錄核心版本、實際設定檔路徑、監聽位址與 mixed-port。可用
mihomo -v查看版本。 - 應用程式入口:記錄瀏覽器使用系統代理或手動代理,以及終端機是否保留代理變數。
- 解析路徑:記錄系統 DNS、核心 DNS 監聽連接埠、是否使用 fake-ip,以及瀏覽器是否啟用安全 DNS。
- 出站結果:記錄測試網域命中的規則、實際節點與錯誤發生時間,不要記錄訂閱金鑰。
- 復原設定:將 debug 日誌恢復為日常層級,並撤銷臨時全域模式與不再需要的測試變更。
最能區分問題來源的判斷方式是:明確指定代理後仍失敗,先檢查核心與出站;明確指定代理成功但瀏覽器失敗,先檢查應用程式入口;只有 TUN 失敗,先檢查透明接管;只有本機解析失敗,再沿著系統 DNS 路徑排查。若要重新建立基本設定,請依照快速入門先完成最精簡的可用連線,再逐項恢復規則、Provider 與 TUN。