Clash API 節點自動切換:健康檢查與故障轉移實戰

想讓 Clash 在節點失效時自動改走可用線路?本指南以 external-controller API 為核心,示範如何讀取代理群組、執行延遲測試、建立健康檢查腳本,並整合排程、權限控管與日誌分析,適合開發者及網路管理員進行進階配置。

先建立自動切換的整體模型

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-testfallbackload-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 或健康檢查網址;若主要使用特定服務,則應另外測試該服務的實際連線品質。

若希望把多個地區的節點先分組,再由上層群組統一選擇,可以建立「亞洲自動」「歐洲自動」等子群組,最後讓「總代理」引用這些子群組。這種結構比把數十個節點全部塞進單一群組更容易閱讀,也方便日後排除某個地區或調整測試策略。

透過 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 秒,除非新節點也連續失敗,否則不要立即切回。

  1. 呼叫 /proxies 取得群組目前選擇與候選節點。
  2. 排除名稱不存在、明確停用或上一輪剛切出的節點。
  3. 逐一呼叫延遲 API,將逾時、連線拒絕與非 2xx 回應記為失敗。
  4. 要求候選節點連續通過至少兩次測試,或達到設定的延遲優勢。
  5. 使用 PUT /proxies/{group} 切換,並記錄切換前後名稱與原因。
  6. 切換後重新讀取群組狀態,確認核心實際接受了新的節點。

腳本可以使用 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 timercron 排程;Windows 可使用「工作排程器」;macOS 可使用 launchd。排程頻率不宜與核心健康檢查完全重疊,例如核心已每 30 秒測試一次,外部腳本可以每 5 分鐘檢查整體狀態,而不是每秒輪詢 API。這能降低 CPU、連線與日誌噪音,也避免多個腳本同時修改同一代理群組。

API 密鑰保護與常見錯誤排查

external-controller 一旦可從區域網路存取,就等同暴露一個可以讀取連線狀態、查看代理名稱,甚至切換代理的管理介面。即使控制器只繫結本機,也不應省略 secret。密鑰建議使用至少 32 個字元的隨機字串,並避免使用訂閱權杖、電子郵件、裝置名稱或容易猜測的固定文字。

錯誤表現 常見原因 檢查方向
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-testfallback 以 30~300 秒間隔執行健康檢查,保證一般故障能自動處理;第二層腳本每 5~10 分鐘讀取群組與延遲狀態,只在連續失敗、節點大幅退化或需要通知時才介入。這種分工比讓腳本每幾秒強制選擇最低延遲節點更穩定。

  1. 在 FlClash 中確認 mihomo 核心版本、代理監聽連接埠與控制器連接埠。
  2. external-controller 綁定至 127.0.0.1,設定隨機 API 密鑰。
  3. 先以兩至五個可靠節點建立 url-testfallback 群組。
  4. 使用同一個 HTTPS 測試網址,設定 5000 毫秒逾時與合適的檢查間隔。
  5. 透過 /version/proxies/delay 逐項測試 API。
  6. 確認 PUT 切換後,實際規則引用的群組已顯示新節點。
  7. 將密鑰放入環境變數或作業系統的受限設定檔,再加入排程。
  8. 保留切換時間、原節點、目標節點、測試延遲與錯誤碼,方便日後調整。

完成後不要只觀察一次延遲數字。至少在日間與夜間各觀察一段時間,記錄節點的成功率、平均延遲、最高延遲與切換次數。如果一天內切換數十次,通常代表測試網址不合適、容忍值太低、候選節點品質接近,或本地網路本身正在波動。此時優先提高穩定性門檻,而不是繼續縮短檢查間隔。

對多數個人使用情境而言,一份清楚的 YAML、受保護的本機 API、合理的健康檢查 URL,以及具備冷卻時間的排程腳本,就足以建立可靠的節點故障轉移。當自動機制出現異常時,也能沿著「核心是否啟動、API 是否可達、群組是否存在、節點是否通過測試、規則是否引用群組」這條路徑逐層定位,不必盲目重裝客戶端或反覆更換訂閱。

FlClash 下載入口 查看各平台用戶端