为什么要用 Clash API 自动切换节点

当节点数量较少、使用时间固定时,手动打开 Clash Verge 或 Mihomo 面板切换节点并不困难;但一旦进入长期下载、CI 构建、远程开发、家庭网关或无人值守服务器场景,手动操作很快就会变成可靠性瓶颈。节点可能在夜间出现丢包,某个出口的延迟可能突然升高,机场订阅也可能在更新后改变节点名称。如果程序只是继续使用已经失效的节点,表面上看 Clash 仍在运行,实际业务却会不断超时、重试,甚至把一个短暂的线路波动放大成整晚的任务失败。

Clash 的外部控制 API提供了一个比模拟鼠标点击更稳定的自动化入口。脚本可以读取代理组当前选择的节点,调用健康检查接口测量候选节点,再通过 REST API 修改指定策略组的活动成员。这样做的关键并不是「每隔几秒寻找延迟最低的节点」,而是建立一条可审计的决策链:先确认 Clash 核心正在运行,再确认候选节点属于目标策略组,然后检查延迟、HTTP 状态、丢包与连续失败次数,最后才执行切换并记录结果。

需要注意,Clash API 通常由本地控制端口提供服务,常见形式是 127.0.0.1:9090,但实际端口要以配置文件中的 external-controller 为准。API 端口并不是代理端口,不能把 mixed-portsocks-port 或 HTTP 代理端口直接当成控制接口使用。Mihomo 还可能启用 HTTPS 控制器、Unix socket 或局域网监听;脚本应先识别当前客户端的实现方式,再选择对应请求地址。

先明确自动化边界:节点自动切换只负责改变策略组成员,不会修复失效订阅、错误规则、DNS 污染或系统代理未启用等问题。自动切换前必须确认手动选择每个候选节点时业务都能正常访问,否则脚本只会在多个坏节点之间循环。

API 认证、策略组与 YAML 基础配置

脚本化配置的第一步是让 Clash 暴露一个可控但不公开的 API。建议只监听本机回环地址,并设置强度足够的密钥。一个适合本机自动化的配置片段如下,具体字段仍应以你使用的 Clash 或 Mihomo 版本为准:

控制端口配置示例

external-controller: 127.0.0.1:9090
secret: "replace-with-a-long-random-secret"
external-ui: ui
mode: rule
log-level: info

external-controller决定 API 服务监听在哪里。若只给本机脚本使用,127.0.0.10.0.0.0安全得多,因为局域网内其他设备无法直接访问控制接口。secret会通过 HTTP 请求头 Authorization: Bearer 发送。不要把密钥写进公开仓库、截图、Shell 历史或监控日志,也不要为了测试方便直接删除认证字段。若确实需要从另一台管理机控制家庭网关,应优先使用 SSH 隧道或受限防火墙,而不是把 API 端口裸露到公网。

自动切换依赖策略组,因此要先确认组的类型与名称。一个常见的策略组结构如下:

策略组与节点引用示例

proxy-groups:
  - name: AUTO_MAIN
    type: select
    proxies:
      - node-tokyo-01
      - node-singapore-02
      - node-seoul-03
      - DIRECT

对 API 来说,AUTO_MAIN是策略组名称,node-tokyo-01等字符串是组成员名称。脚本不能依赖列表中的位置,因为订阅更新后节点顺序可能变化;更稳妥的做法是按名称、地区标签或自定义前缀筛选候选节点。若机场自动生成的节点名称包含 emoji、空格或括号,必须从 API 返回值中原样读取,不要在脚本里凭感觉重写。名称只要有一个字符不同,切换请求就可能返回四百错误。

常用的只读接口包括获取全部代理、读取某个代理组以及查看版本信息。不同内核版本的返回结构可能略有差异,因此脚本要对响应状态码和 JSON 字段做校验,不能收到非空响应就直接认为请求成功。一个典型的切换请求逻辑是向策略组资源发送 PUT 请求,并提交目标节点名称:

GET  /proxies
GET  /proxies/AUTO_MAIN
PUT  /proxies/AUTO_MAIN
     {"name":"node-tokyo-01"}

URL 中的策略组名称需要进行编码。尤其是组名包含空格、斜杠、中文或特殊符号时,不能直接拼接到路径中。实际工程中应使用 Python 的 urllib.parse.quote,并对组名、节点名和响应内容设置合理的长度限制,避免异常数据污染日志。切换之前还要读取当前选中项;如果目标节点已经是当前节点,脚本应记录「无需切换」并退出,而不是重复发送请求造成不必要的连接重建。

用 Python 构建健康检查与节点选择器

一个可靠的脚本至少要分成四层:API 客户端、候选节点过滤、健康检查、切换与记录。把所有逻辑写在一个巨大的 main() 中,短期看似方便,后续却很难替换探针地址或调整评分规则。API 客户端只负责请求与认证;过滤器只负责决定哪些节点可以参选;健康检查负责返回可比较的数据;决策器根据数据判断是否达到切换阈值。

健康检查不应只测一个抽象的 TCP 延迟。TCP 握手成功,不能证明目标网站可以完成 TLS;TLS 成功,也不能证明 HTTP 请求不会被重置。更实用的探针通常是一个稳定、响应体较小的 HTTPS 地址,例如你实际业务依赖的健康检查 URL。检查结果至少应包含状态码、总耗时、异常类型和时间戳。若业务是长连接或流式请求,还应单独验证连接能否保持,而不是把一次快速的首页请求当成完整结论。

Python 健康检查示例

import os
import time
import requests

API = "http://127.0.0.1:9090"
TOKEN = os.environ["CLASH_API_SECRET"]
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

def check_node(group, node, probe_url, timeout=8):
    started = time.perf_counter()
    try:
        response = requests.get(
            f"{API}/proxies/{group}",
            headers=HEADERS,
            timeout=timeout
        )
        response.raise_for_status()
        return {
            "name": node,
            "ok": True,
            "elapsed_ms": round((time.perf_counter() - started) * 1000)
        }
    except requests.RequestException as exc:
        return {"name": node, "ok": False, "error": type(exc).__name__}

上面的代码只是 API 请求骨架,真正的节点测速应调用当前内核支持的延迟测试接口,或让候选节点通过独立的代理连接访问探针。不能把「读取策略组成功」误当成「节点健康」,因为读取策略组只证明控制 API 可用,并没有证明目标节点能建立出站连接。对于支持延迟测试的 Mihomo 版本,应先从 /proxies/节点名/delay 获取结果;若内核版本不支持该路径,则可为每个节点创建临时代理请求,但要避免同时发起过多测试。

节点选择最好使用硬门槛加评分,而不是单纯选择最小延迟。硬门槛可以包括:探针必须返回二百级状态码、延迟不得超过一千五百毫秒、连续失败次数不能达到上限、节点名称不能匹配维护或过期标记。通过门槛后再计算评分,例如延迟占百分之六十、近五次成功率占百分之三十、最近一次切换惩罚占百分之十。这样可以避免一个刚好测出低延迟但不稳定的节点频繁抢占当前连接。

API 返回的代理组成员可能包含嵌套策略组,而不是全部真实节点。脚本需要明确是否允许递归展开。对于生产环境,更推荐把一个专门的自动选择组只绑定真实节点,另一个业务组再引用它。这样自动化程序不会误把「地区选择」「手动备用」这类上层组当成可测速节点,调试日志也更容易理解。

定时任务、日志审计与故障保护

脚本能手动执行成功后,再接入定时任务。Linux 可以使用 systemd timercron,macOS 可使用 launchd,Windows 则可使用任务计划程序。不要让任务每分钟无限制运行;自动切换本质上是一个控制回路,检查周期太短会增加 API 请求、节点握手和业务连接重置。多数桌面使用场景可以从五分钟或十分钟开始,服务器则根据业务对连续性的要求调整。

cron 调度示例

*/10 * * * * /usr/bin/flock -n /tmp/clash-switch.lock \
  /opt/clash/bin/switch-node.py >> /var/log/clash-switch.log 2>&1

flock用于避免上一次检查还没有结束时,下一次任务再次启动。Windows 任务计划程序也应启用「如果任务已在运行,则不要启动新实例」之类的并发限制。若检查脚本需要访问订阅文件、环境变量或用户目录,必须使用绝对路径,并明确指定工作目录;定时任务的环境变量通常比交互式 Shell 少,直接复制终端命令往往会出现手动执行正常、定时执行失败的情况。

日志至少应记录检查时间、策略组、当前节点、候选节点、探针结果、切换原因、API 状态码和脚本版本。不要记录完整的 Authorization 请求头,也不要把订阅 URL 写入普通日志,因为订阅链接经常本身就包含访问凭证。可以把日志输出为 JSON Lines,便于后续交给 Loki、ELK 或其他监控系统分析。连续切换次数、所有候选节点同时失败、API 无法连接等情况应触发告警,而不是静默地反复重试。

安全底线:自动化脚本拥有改变代理出口的权限,API 密钥应放在环境变量、系统密钥环或权限为六百的独立配置文件中。脚本文件、日志文件与定时任务配置都不应允许普通无关用户写入,否则攻击者可能通过修改候选节点、探针地址或切换请求,把流量导向未知出口。

故障保护可以采用「保留当前节点」和「回退备用节点」两种策略。若当前节点检查失败,但备用节点尚未确认健康,最安全的动作通常是保持原状态并告警,而不是盲目切换到列表第一项。只有当多个独立探针都确认当前节点不可用时,才进入备用选择流程。切换完成后还要再次读取策略组,验证 Clash 实际接受了目标名称;请求返回成功不代表配置已按预期生效,二次读取是成本很低的闭环确认。

最后应安排一次人工演练:暂时阻断当前节点、观察脚本是否等待冷却时间、确认新节点被选中,再恢复原节点并检查是否会立即来回切换。还要测试 API 端口关闭、密钥错误、节点名称包含特殊字符、所有探针超时以及脚本进程被中断等情况。只有这些异常路径都有明确结果,自动切换才适合用于远程服务器或无人值守任务。

与只提供手动下拉选择的轻量代理客户端相比,Clash Verge、Clash Verge Rev 或部分旧版 Clash for Windows 更适合临时切换,却往往需要用户持续盯着界面;单纯依靠 url-test 又可能缺少业务探针、失败冷却和审计日志。Clash V.CORE 在 API 控制、Mihomo 配置兼容、策略组管理与脚本化运维之间提供了更完整的落点,既能保留图形界面的可视化排障,也能让 Python 和定时任务承担重复工作。如果你准备把本文流程真正部署到电脑或服务器上,可以先前往前往下载,再用一份隔离配置验证 API 认证、健康检查和回退逻辑。

// 编辑推荐

Clash V.CORE — 让节点切换进入自动化流程

从可视化策略组到 API 控制与 Mihomo 配置兼容,为脚本化节点管理提供稳定的运行基础。

  • 兼容策略组与节点自动管理
  • 支持 API 认证与状态核验
  • 便于接入 Python 定时任务
  • 清晰查看连接日志与切换结果
  • 适合桌面与无人值守场景
获取 Clash V.CORE →