先建立自動切換的整體模型
Clash 節點自動切換並不是單純「測到哪個節點延遲最低,就切換到哪個節點」。一個可長期運作的機制,通常包含四個部分:mihomo 核心提供外部控制 API、YAML 代理群組定義切換策略、健康檢查負責判斷節點是否可用,以及排程腳本在需要時讀取狀態並執行切換。任何一層的設定不完整,都可能造成節點看似正常,實際連線卻反覆中斷。
在 FlClash 或其他支援 mihomo 的客戶端中,先確認目前使用的核心確實支援 external-controller 與代理群組健康檢查。不同客戶端的介面名稱可能是「外部控制」「External Controller」或「控制器位址」,但核心設定通常仍寫在 YAML 中。常見的本機服務如下:
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
external-controller: 127.0.0.1:9090
secret: replace-with-a-long-random-secret
mixed-port 是給瀏覽器與其他應用程式使用的 HTTP、SOCKS 混合代理連接埠;external-controller 則是給客戶端或腳本控制核心的 API 連接埠,兩者用途不同。腳本應呼叫 9090 之類的控制連接埠,而不是把 API 請求送到 7890。若控制器繫結在 127.0.0.1,只有本機程式可以存取,適合個人電腦使用;若改成 0.0.0.0:9090,就必須額外處理區域網路防火牆與密鑰外洩風險。
先區分三種切換需求
- 延遲選擇:定期測試多個節點,選擇探測結果較快的節點,適合節點品質差異明顯但不一定會完全斷線的情境。
- 故障轉移:目前節點無法連線時,才切換到下一個可用節點,適合需要維持工作階段穩定性的情境。
- 負載分攤:讓多個節點依順序或負載分配流量,不以單次延遲作為唯一選擇條件,適合多裝置或多服務使用。
這三種需求分別對應 url-test、fallback 與 load-balance 等策略。若只是希望日常瀏覽自動選擇較快節點,可以先使用 YAML 內建的代理群組;只有在需要自訂判斷規則、記錄切換原因或通知服務時,才需要額外撰寫 API 腳本。
用 YAML 建立延遲測試與故障轉移
最容易維護的做法,是先把節點放入一個代理提供者或直接列在 proxies,再用 proxy-groups 建立自動選線群組。以下範例使用直接列出的節點名稱,實際使用時請將名稱替換成訂閱產生的節點名稱。url-test 會定期向指定 URL 發出測試,依回應延遲選擇可用節點;fallback 則依列出順序選擇第一個通過測試的節點。
proxies:
- name: "東京-01"
type: ss
server: example-one.invalid
port: 443
cipher: aes-128-gcm
password: change-me
- name: "大阪-01"
type: trojan
server: example-two.invalid
port: 443
password: change-me
sni: example-two.invalid
proxy-groups:
- name: "自動選線"
type: url-test
proxies:
- "東京-01"
- "大阪-01"
url: "https://www.gstatic.com/generate_204"
interval: 300
tolerance: 80
timeout: 5000
- name: "故障轉移"
type: fallback
proxies:
- "自動選線"
- "東京-01"
- "大阪-01"
url: "https://www.gstatic.com/generate_204"
interval: 30
timeout: 5000
rules:
- MATCH,故障轉移
interval: 300 代表每 300 秒重新檢查一次;故障轉移群組可使用較短的 30 秒間隔,以便更快離開失效節點。timeout: 5000 是單次測試的逾時時間,單位為毫秒。網路品質不穩定時,過短的逾時值容易把只是暫時延遲的節點判斷為故障;過長則會讓切換反應變慢。一般桌面使用可先從 3000~5000 毫秒開始,再依實際日誌調整。
tolerance 與測試網址的實際影響
tolerance 是延遲差異容忍值,單位通常為毫秒。假設目前節點測得 90 ms,另一節點測得 70 ms,當容忍值為 30 時,差距未超過門檻,核心不一定會立刻切換;當容忍值為 10 時,則更容易選擇測試結果較低的節點。適度提高容忍值,可以避免延遲在 70~100 ms 之間小幅波動時頻繁切換。
測試 URL 應選擇穩定、回應內容簡單且距離使用者網路環境合理的 HTTPS 端點。不同網址可能受到 DNS、CDN、地區封鎖或服務端限流影響,因此測試成功只代表「代理可以到達這個網址」,不代表所有網站與串流服務都同樣順暢。若日常用途是一般網頁,可以使用回應快速的 204 或健康檢查網址;若主要使用特定服務,則應另外測試該服務的實際連線品質。
- 測試網址不要選擇需要登入、會跳轉或回傳大型內容的頁面。
- 所有候選節點盡量使用同一測試 URL,避免不同目標造成結果不可比較。
- 將
interval設為 30 秒不代表每 30 秒都應切換,仍需配合容忍值與連續失敗判斷。 - 若節點數量超過 30 個,過短的測試間隔可能增加連線數與服務端請求壓力。
- 訂閱更新後要檢查代理群組中的節點名稱是否仍存在,名稱變更會讓群組引用失效。
若希望把多個地區的節點先分組,再由上層群組統一選擇,可以建立「亞洲自動」「歐洲自動」等子群組,最後讓「總代理」引用這些子群組。這種結構比把數十個節點全部塞進單一群組更容易閱讀,也方便日後排除某個地區或調整測試策略。
透過 Clash API 讀取狀態並切換節點
mihomo 的外部控制介面使用 HTTP API。最基本的檢查是呼叫 /version,確認控制器可連線;再呼叫 /proxies,取得目前所有代理與代理群組。API 若設定了 secret,請在請求標頭加入 Authorization: Bearer 密鑰。以下示範使用本機控制器,網址中的 example-group 只是群組名稱示例。
curl -sS \
-H "Authorization: Bearer replace-with-a-long-random-secret" \
http://127.0.0.1:9090/version
curl -sS \
-H "Authorization: Bearer replace-with-a-long-random-secret" \
http://127.0.0.1:9090/proxies
延遲測試 API 通常使用 /proxies/{proxy} 的 delay 子路徑,並帶上測試 URL 與逾時參數。節點名稱包含空格、斜線或特殊字元時,必須先進行 URL 編碼,不能直接把原始名稱拼接到路徑中。
curl -G -sS \
-H "Authorization: Bearer replace-with-a-long-random-secret" \
--data-urlencode "url=https://www.gstatic.com/generate_204" \
--data-urlencode "timeout=5000" \
"http://127.0.0.1:9090/proxies/東京-01/delay"
要切換代理群組目前使用的節點,則對 /proxies/{group} 發送 HTTP PUT,請求內容是 JSON 的 name 欄位。群組名稱同樣需要編碼。切換前應先確認目標節點確實存在於該群組,否則核心可能回傳錯誤,或切換後仍維持原本的選擇。
curl -sS -X PUT \
-H "Authorization: Bearer replace-with-a-long-random-secret" \
-H "Content-Type: application/json" \
-d '{"name":"大阪-01"}' \
"http://127.0.0.1:9090/proxies/故障轉移"
腳本判斷時不要只看單次延遲
自訂腳本的判斷邏輯至少應包含目前節點、候選節點、測試結果、連續失敗次數與冷卻時間。單次測試失敗可能只是瞬間丟包,若腳本立即切換,反而會造成頻繁跳轉。較穩定的規則是:同一節點連續兩或三次逾時,才將它標記為暫時失效;切換後至少維持 60~180 秒,除非新節點也連續失敗,否則不要立即切回。
- 呼叫
/proxies取得群組目前選擇與候選節點。 - 排除名稱不存在、明確停用或上一輪剛切出的節點。
- 逐一呼叫延遲 API,將逾時、連線拒絕與非 2xx 回應記為失敗。
- 要求候選節點連續通過至少兩次測試,或達到設定的延遲優勢。
- 使用
PUT /proxies/{group}切換,並記錄切換前後名稱與原因。 - 切換後重新讀取群組狀態,確認核心實際接受了新的節點。
腳本可以使用 Python、Node.js 或作業系統排程工具實作,但不要把密鑰直接寫入公開程式碼。以下是適合排程腳本採用的請求概念,重點在於逾時、狀態碼與錯誤內容都要被記錄,而不是只捕捉程式例外:
import os
import requests
controller = "http://127.0.0.1:9090"
secret = os.environ["CLASH_API_SECRET"]
headers = {"Authorization": f"Bearer {secret}"}
response = requests.get(
f"{controller}/version",
headers=headers,
timeout=5
)
response.raise_for_status()
print(response.json())
在 Linux 可使用 systemd timer 或 cron 排程;Windows 可使用「工作排程器」;macOS 可使用 launchd。排程頻率不宜與核心健康檢查完全重疊,例如核心已每 30 秒測試一次,外部腳本可以每 5 分鐘檢查整體狀態,而不是每秒輪詢 API。這能降低 CPU、連線與日誌噪音,也避免多個腳本同時修改同一代理群組。
API 密鑰保護與常見錯誤排查
external-controller 一旦可從區域網路存取,就等同暴露一個可以讀取連線狀態、查看代理名稱,甚至切換代理的管理介面。即使控制器只繫結本機,也不應省略 secret。密鑰建議使用至少 32 個字元的隨機字串,並避免使用訂閱權杖、電子郵件、裝置名稱或容易猜測的固定文字。
- 只允許本機使用:優先設定
external-controller: 127.0.0.1:9090,不要為了方便直接監聽所有介面。 - 必須遠端控制時:使用防火牆限制來源 IP,並透過安全的 VPN 或 SSH 隧道存取,不要直接把 9090 轉發到公網。
- 避免寫入日誌:不要在錯誤日誌、Shell 歷史或 CI 輸出中打印完整的 Authorization 標頭。
- 分離權限:能只在本機執行的腳本,不要使用需要對外監聽的控制器設定。
- 輪替密鑰:懷疑密鑰外洩時,立即修改 YAML 並重啟核心,再更新腳本的環境變數。
| 錯誤表現 | 常見原因 | 檢查方向 |
|---|---|---|
Connection refused |
核心未啟動、連接埠錯誤或控制器沒有監聽 | 檢查核心日誌與 external-controller,確認實際連接埠不是 9091 或其他值 |
401 Unauthorized |
密鑰缺少、拼寫錯誤或 Bearer 格式不正確 | 確認標頭為 Authorization: Bearer 密鑰,不要多加引號或換行 |
404 Not Found |
API 路徑、群組名稱或節點名稱不正確 | 先讀取 /proxies,從回傳 JSON 複製實際名稱並進行 URL 編碼 |
400 Bad Request |
PUT 請求不是有效 JSON,或目標節點不屬於該群組 | 確認 Content-Type、JSON 格式與群組成員清單 |
| 測試結果忽高忽低 | 測試 URL、DNS、UDP 路徑或本地網路本身不穩定 | 增加容忍值,改用穩定的 HTTPS 測試網址,並觀察連續多輪結果 |
| 切換成功但應用程式無流量 | 規則未引用該群組、系統代理未啟用或 TUN 路由未接管 | 檢查 rules、系統代理、TUN 狀態與實際監聽連接埠 |
測試時可以先用 /version 確認 API 通道,再用 /proxies 確認群組,最後才執行延遲探測與 PUT 切換。不要一開始就把所有動作放進無限迴圈,否則一旦群組名稱寫錯,腳本會重複產生錯誤請求。建議先以手動指令完成一次讀取與切換,確認結果後再加入排程。
一套適合日常使用的落地流程
實作時可以採用「核心負責第一層、腳本負責第二層」的架構。第一層由 url-test 或 fallback 以 30~300 秒間隔執行健康檢查,保證一般故障能自動處理;第二層腳本每 5~10 分鐘讀取群組與延遲狀態,只在連續失敗、節點大幅退化或需要通知時才介入。這種分工比讓腳本每幾秒強制選擇最低延遲節點更穩定。
- 在 FlClash 中確認 mihomo 核心版本、代理監聽連接埠與控制器連接埠。
- 將
external-controller綁定至127.0.0.1,設定隨機 API 密鑰。 - 先以兩至五個可靠節點建立
url-test或fallback群組。 - 使用同一個 HTTPS 測試網址,設定 5000 毫秒逾時與合適的檢查間隔。
- 透過
/version、/proxies與/delay逐項測試 API。 - 確認 PUT 切換後,實際規則引用的群組已顯示新節點。
- 將密鑰放入環境變數或作業系統的受限設定檔,再加入排程。
- 保留切換時間、原節點、目標節點、測試延遲與錯誤碼,方便日後調整。
完成後不要只觀察一次延遲數字。至少在日間與夜間各觀察一段時間,記錄節點的成功率、平均延遲、最高延遲與切換次數。如果一天內切換數十次,通常代表測試網址不合適、容忍值太低、候選節點品質接近,或本地網路本身正在波動。此時優先提高穩定性門檻,而不是繼續縮短檢查間隔。
對多數個人使用情境而言,一份清楚的 YAML、受保護的本機 API、合理的健康檢查 URL,以及具備冷卻時間的排程腳本,就足以建立可靠的節點故障轉移。當自動機制出現異常時,也能沿著「核心是否啟動、API 是否可達、群組是否存在、節點是否通過測試、規則是否引用群組」這條路徑逐層定位,不必盲目重裝客戶端或反覆更換訂閱。