Clash 的策略組可以透過 url-testfallback 自動選擇節點,但這些功能主要依賴內建測速與固定策略。當你希望按照業務規則、服務狀態、延遲門檻或外部監控結果來切換節點時,就需要使用 external-controller 提供的 RESTful API。它能讓腳本查詢策略組狀態、觸發節點測速,並在不中斷 Clash 核心程序的情況下完成節點切換。

本文以 Mihomo 與支援 API 的 Clash 客戶端為例,從 external-controller 的安全設定開始,逐步建立節點切換流程,並示範如何使用 Shell 與 Python 腳本實作延遲判斷、故障轉移、冷卻時間與日誌記錄。這套方法適合長時間下載、家庭伺服器、遠端工作站,以及需要集中管理多個 Clash 實例的進階使用者。

External Controller 與 API 架構

external-controller 是 Clash 對外提供管理介面的 HTTP 伺服器。Dashboard、手機管理工具和自動化腳本,本質上都是透過這個介面讀取狀態或發送控制指令。它與代理流量本身是兩條不同的通道:代理連線經過策略組轉發,而 API 請求只負責管理核心狀態。

啟用 API 時,最重要的是確認監聽地址與認證方式。僅在本機使用時,應優先綁定 127.0.0.1;若綁定 0.0.0.0,就代表區域網路中可能有其他裝置可以嘗試連線,必須設定足夠複雜的 secret,並搭配防火牆限制來源。

啟用安全的 External Controller
# 僅供本機腳本與 Dashboard 使用
external-controller: 127.0.0.1:9090
secret: change-this-to-a-long-random-token

# 若需要區域網路管理,請搭配防火牆與強密碼
# external-controller: 0.0.0.0:9090

API 使用 Bearer Token 認證。假設控制器位於 127.0.0.1:9090,金鑰為配置中的 secret,所有需要權限的請求都應加入以下標頭:

測試 API 是否可用
curl -H "Authorization: Bearer change-this-to-a-long-random-token" \
  http://127.0.0.1:9090/version

/version 通常不需要複雜參數,適合用來確認連接埠、路由與 Token 是否正確。若返回 JSON 版本資訊,表示腳本已經可以與 Clash 通訊。常用 API 還包括 /proxies(取得所有代理與策略組)、/proxies/{name}(取得指定策略組)、/group/{name}(部分版本支援的策略組操作)以及 /proxies/{group} 的 PUT 切換請求。不同核心版本的端點細節可能略有差異,實際使用前應先在本機以 GET 查詢確認。

不要公開暴露未保護的 API:secret 留空,任何能連到控制器的人都可能切換節點、讀取連線資訊,甚至修改核心配置。即使只在區域網路使用,也不建議把 9090 連接埠直接轉發到網際網路。

策略組與自動切換的資料流程

自動切換不是簡單地「找到延遲最低的節點就切換」。一個可靠的腳本至少要區分節點、策略組和測速結果三種資料。節點是實際的代理出口,例如香港、日本或新加坡節點;策略組是 Clash 用來承接流量的邏輯名稱,例如 Proxy自動選擇;測速結果則是某個節點在特定測試 URL 上的回應時間。

推薦的處理流程如下:

  1. 先從 /proxies 取得全部代理與策略組,確認目標策略組確實存在。
  2. 讀取策略組目前選中的節點,作為比較基準與故障恢復參考。
  3. 對候選節點發送延遲測試,排除超時、錯誤或不在允許清單內的節點。
  4. 依照最低延遲、地區優先級與穩定性條件計算候選結果。
  5. 只有當新節點比目前節點快超過設定門檻,或目前節點已失效時,才發送切換指令。
  6. 寫入切換時間與結果,進入冷卻期間,避免多個排程程序反覆切換。

在配置檔案中,可以先建立一個明確的策略組,讓腳本只控制這個群組,而不是直接操作單一代理。這樣其他規則仍然可以使用相同的策略組名稱,日後增加或刪除節點時也不必修改每一條規則。

供 API 控制的策略組
proxy-groups:
  - name: API 自動切換
    type: select
    proxies:
      - HK-01
      - HK-02
      - JP-01
      - SG-01
      - DIRECT

rules:
  - MATCH,API 自動切換

使用 select 而不是直接使用 url-test,是為了把「判斷邏輯」交給外部腳本。若你的需求只是固定週期選擇最低延遲節點,url-test 已經足夠;若要加入節點地區、串流解鎖、工作時段或錯誤率等條件,API 控制會更有彈性。

查詢節點、延遲與觸發測速

取得所有代理資料時,可以先呼叫 /proxies。回應通常是一個以名稱為鍵的 JSON 物件,其中策略組會包含 typeallnow 欄位。all 是該群組可選的節點清單,now 是目前使用中的節點。腳本不應假設所有版本回傳欄位完全一致,最好先檢查鍵是否存在。

查詢策略組與目前節點
curl -s \
  -H "Authorization: Bearer change-this-to-a-long-random-token" \
  "http://127.0.0.1:9090/proxies/API%20%E8%87%AA%E5%8B%95%E5%88%87%E6%8F%9B"

對單一節點進行延遲測試時,Mihomo 常用的 API 形式是 /proxies/{name}/delay,並透過查詢參數指定測速網址與逾時時間。節點名稱可能包含空格、斜線或特殊字元,因此必須進行 URL 編碼,不能直接把原始名稱拼接到路徑中。

測試指定節點延遲
curl -s -G \
  -H "Authorization: Bearer change-this-to-a-long-random-token" \
  --data-urlencode "url=https://www.gstatic.com/generate_204" \
  --data-urlencode "timeout=5000" \
  "http://127.0.0.1:9090/proxies/HK-01/delay"

測速 URL 應選擇回應穩定、內容很小且在目標網路中可達的地址。generate_204 類型的網址適合測量連線建立時間,但它不一定代表串流或大型下載的實際速度。若你的使用情境主要是影音,可以另外建立一個僅用於測速的輕量 HTTPS 端點,避免因第三方服務限速造成誤判。

用 Python 建立延遲門檻與故障轉移

下面的腳本示範一個保守的自動切換器:每次執行時查詢指定策略組,逐一測試候選節點,忽略超過逾時限制的節點;如果目前節點仍然可用,只有當最佳節點至少快 50 毫秒時才切換。這個差值就是延遲門檻,可以防止節點延遲在細微波動時頻繁跳轉。

auto_switch.py
import time
import urllib.parse
import requests

API = "http://127.0.0.1:9090"
TOKEN = "change-this-to-a-long-random-token"
GROUP = "API 自動切換"
CANDIDATES = ["HK-01", "HK-02", "JP-01", "SG-01"]
TEST_URL = "https://www.gstatic.com/generate_204"
TIMEOUT_MS = 5000
TOLERANCE_MS = 50

session = requests.Session()
session.headers.update({"Authorization": f"Bearer {TOKEN}"})


def get_group():
    path = "/proxies/" + urllib.parse.quote(GROUP, safe="")
    response = session.get(API + path, timeout=8)
    response.raise_for_status()
    return response.json()


def get_delay(name):
    path = "/proxies/" + urllib.parse.quote(name, safe="") + "/delay"
    params = {"url": TEST_URL, "timeout": TIMEOUT_MS}
    try:
        response = session.get(API + path, params=params, timeout=8)
        response.raise_for_status()
        return int(response.json()["delay"])
    except (requests.RequestException, KeyError, ValueError):
        return None


def switch_to(name):
    path = "/proxies/" + urllib.parse.quote(GROUP, safe="")
    response = session.put(path, json={"name": name}, timeout=8)
    response.raise_for_status()


group = get_group()
current = group.get("now")
results = {}

for node in CANDIDATES:
    delay = get_delay(node)
    if delay is not None:
        results[node] = delay

if results:
    best = min(results, key=results.get)
    current_delay = results.get(current)

    should_switch = (
        current not in results or
        current_delay is None or
        results[best] + TOLERANCE_MS < current_delay
    )

    if should_switch and best != current:
        switch_to(best)
        print(f"switched: {current} -> {best}, {results[best]} ms")
    else:
        print(f"keep: {current}, results={results}")
else:
    print("no healthy node found")

實際部署時,請把 Token 放在環境變數或權限受控的設定檔,不要直接提交到 Git 儲存庫。腳本中的 PUT 請求只應對策略組發送,請先確認群組名稱,而不是把節點名稱誤當成群組名稱。若 API 回傳 404,通常代表 URL 編碼、策略組名稱或核心版本的端點格式不正確。

門檻不要設定得太小:如果兩個節點只相差 5 至 10 毫秒,切換成本通常高於收益。建議先使用 30 至 80 毫秒的容忍值,再根據實際網路品質調整;對長連線服務來說,穩定性通常比瞬間最低延遲更重要。

排程、冷卻時間與生產環境注意事項

完成腳本後,可以使用 Linux 的 cron 或 systemd timer 定期執行。例如每五分鐘執行一次,比每幾秒測速更適合一般家庭與工作環境。頻率太高不只會增加 API 請求,也可能讓策略組在節點狀態尚未穩定前再次切換,造成已建立的連線被中斷。

使用 cron 每五分鐘執行
*/5 * * * * /usr/bin/python3 /opt/clash/auto_switch.py >> /var/log/clash-auto-switch.log 2>&1

建議在腳本中加入至少一個冷卻機制。最簡單的方式是記錄上次切換時間,在短時間內不允許再次切換;更穩妥的方式是要求新節點連續兩次測速都優於目前節點,才真正發送 PUT 請求。這能避免單次網路抖動、DNS 暫時失敗或測速服務繁忙導致錯誤切換。

錯誤處理方面,應將「目前節點測速失敗」與「所有節點都失敗」分開處理。前者可以立即切換到最快的健康節點;後者則不應把策略組切換到 DIRECT,除非你明確接受流量離開代理。對需要隱私或固定出口 IP 的環境,找不到健康節點時寧可保留原狀並發出警告,也不要無提示地降級直連。

  • 限制候選範圍:不要把訂閱中的所有節點都納入測速,可依地區、協議或用途建立白名單。
  • 記錄切換原因:保留目前節點、候選延遲、切換時間與 API 回應,方便追查頻繁跳轉問題。
  • 避免同時執行:使用 lockfile 或 systemd 的單例機制,防止兩個腳本同時修改同一策略組。
  • 控制 API 權限:本機腳本使用回環地址;遠端控制則搭配 VPN、ACL 與防火牆,不要只依賴 Token。
  • 先觀察再自動化:初期可只記錄測速結果而不切換,確認門檻合理後再開啟 PUT 操作。

當你把 API、健康檢查與策略組結合起來,Clash 就不再只是手動點選節點的代理工具,而能成為一個可監控、可恢復、可依條件決策的流量控制平台。對多數使用者來說,先從單一策略組與五分鐘排程開始,觀察一至兩天的日誌,再逐步加入地區優先級、錯誤率和冷卻時間,是最安全的導入方式。

立即開始

用 Clash 掌控您的流量

支援 Windows、macOS、Linux、Android 與 iOS,靈活規則,開箱即用。

免費下載 查看設定指南 →