配置 2026年7月29日 · 约 12 分钟阅读

Clash API自动切换节点:external-controller进阶配置

通过 Clash external-controller API 构建节点自动切换系统,结合延迟探测、策略组控制与脚本化运维,实现代理故障自动恢复,并掌握鉴权、日志分析和安全加固方法。

external-controller 是什么,为什么适合自动切换节点

Clash 的 external-controller 是一个供外部程序调用的管理接口。客户端启动后,只要在配置文件中监听一个本地地址,脚本、监控程序或其他运维工具就可以通过 HTTP API 查询当前配置、读取代理节点、执行延迟测试,以及切换策略组中的活动节点。它不负责承载代理流量,而是负责「管理正在运行的 Clash」。

手动切换节点适合偶尔使用,但在节点质量波动、家庭服务器长期运行或多台设备共享代理时,人工观察并不可靠。某个节点可能在上午延迟正常,晚上出现丢包;客户端界面仍显示运行中,但实际请求已经频繁超时。通过 external-controller,可以让程序定时测试候选节点,在延迟过高、连接失败或连续错误时自动切换到备用节点,同时保留人工随时接管的能力。

需要注意的是,不同客户端使用的内核和 API 版本可能存在差异。Clash Verge Rev、Mihomo、部分 Clash for Windows 分支通常提供较完整的控制接口,而旧版客户端可能只支持部分端点。本文以常见的 Clash/Mihomo REST API 为例,重点讲解通用思路;实际部署前,建议先在客户端设置页面确认控制器地址、认证方式和 API 可用范围。

第一步:开启 external-controller 并设置鉴权

编辑 Clash 配置文件,在顶层加入控制器监听地址。最稳妥的做法是只监听本机回环地址,避免局域网内的其他设备直接取得代理控制权:

基础配置示例

external-controller: 127.0.0.1:9090
secret: "change-this-to-a-long-random-secret"

127.0.0.1:9090 表示只有运行 Clash 的本机可以访问接口。如果你确实需要从局域网中的监控服务器管理 Clash,可以将地址改为局域网网卡地址或 0.0.0.0:9090,但必须同时配置防火墙白名单、强随机密钥和访问来源限制。直接把没有密钥的控制器暴露到公网,等同于把节点切换、配置修改和连接管理权限交给任何能够访问端口的人。

修改配置后,重新加载配置或重启客户端,然后使用一个简单请求检查接口是否可达。带有 secret 时,需要在 HTTP 请求头中加入 Authorization

curl -s \
  -H "Authorization: Bearer change-this-to-a-long-random-secret" \
  http://127.0.0.1:9090/version

如果返回 JSON 并包含 Clash 或 Mihomo 的版本信息,说明控制器已经启动。若出现连接被拒绝,先检查客户端是否真的加载了这份配置;若返回 401 或 403,则重点检查密钥是否完全一致,包括前后空格、引号和大小写。部分 GUI 会把控制器配置放在自己的设置页中,直接编辑订阅生成的 YAML 可能在下一次更新时被覆盖,因此最好使用客户端提供的覆写、Mixin 或外部控制器设置。

安全提醒

不要把 secret 写成空字符串,也不要使用用户名、生日或订阅名称作为密钥。控制器接口不仅能读取节点信息,还可能修改代理组、重载配置和关闭连接。生产环境建议使用至少 32 位随机字符串,并将配置文件权限限制为当前用户可读。

第二步:掌握节点查询、延迟探测与策略组控制

自动切换的核心流程可以拆成三件事:先查询策略组及候选节点,再对候选节点进行延迟测试,最后向目标策略组发送切换请求。常用接口如下表所示:

用途 请求 说明
查看版本 GET /version 确认控制器是否在线
查看全部代理 GET /proxies 返回节点、策略组和当前选中项
测试延迟 GET /proxies/{name}/delay 对指定节点访问测试 URL
切换策略组 PUT /proxies/{group} 将策略组切换到指定代理
查看连接 GET /connections 观察当前连接、规则和出站节点
关闭连接 DELETE /connections/{id} 清理指定的长连接或异常连接

节点名称和策略组名称可能包含中文、空格、斜杠或特殊符号,拼接 URL 时必须进行 URL 编码,不能直接把原始名称塞进路径。延迟测试通常需要指定一个稳定的测试地址和超时时间,例如:

curl -sG \
  -H "Authorization: Bearer change-this-to-a-long-random-secret" \
  --data-urlencode "url=https://www.gstatic.com/generate_204" \
  --data-urlencode "timeout=5000" \
  "http://127.0.0.1:9090/proxies/节点名称/delay"

返回结果中的 delay 通常以毫秒表示。数值越低不一定代表体验越好,因为延迟测试只反映某个测试地址在某一时刻的首包响应,无法完整代表视频缓冲、下载速度、晚高峰丢包或特定网站的可用性。因此自动切换不应只设置一个「最低延迟」条件,还应该结合失败次数、最低延迟阈值、连续稳定时间和冷却时间。

切换策略组时,目标必须是实际存在的策略组,而不是单个节点。假设策略组名称为「自动选择」,可以使用以下请求:

curl -X PUT \
  -H "Authorization: Bearer change-this-to-a-long-random-secret" \
  -H "Content-Type: application/json" \
  -d '{"name":"香港-01"}' \
  "http://127.0.0.1:9090/proxies/自动选择"

如果接口返回成功,客户端界面的策略组选择通常会同步更新。若请求成功但流量仍然不通,检查规则实际引用的是否正是这个策略组。有些配置同时存在「节点选择」「国外流量」「流媒体」等多个组,只切换其中一个并不会影响所有请求。

第三步:用脚本实现延迟筛选和故障恢复

一个可维护的自动切换脚本,不应该在每次发现一次高延迟时立即换节点,否则网络短暂抖动会造成频繁切换、连接重置和缓存失效。更合理的策略是:先读取指定策略组,排除「DIRECT」「REJECT」和嵌套策略组;然后按顺序测试候选节点;只有当当前节点连续失败或延迟超过阈值时,才选择满足条件的备用节点。

下面的 Python 示例展示了基本实现。它使用标准库发送请求,不需要额外安装依赖。示例中的策略组、密钥和测试地址都应替换为自己的值:

import time
import requests

API = "http://127.0.0.1:9090"
SECRET = "change-this-to-a-long-random-secret"
GROUP = "自动选择"
TEST_URL = "https://www.gstatic.com/generate_204"
MAX_DELAY = 800
TIMEOUT = 5

HEADERS = {"Authorization": f"Bearer {SECRET}"}

def get_proxies():
    response = requests.get(f"{API}/proxies", headers=HEADERS, timeout=TIMEOUT)
    response.raise_for_status()
    return response.json()["proxies"]

def measure(name):
    response = requests.get(
        f"{API}/proxies/{requests.utils.quote(name, safe='')}/delay",
        headers=HEADERS,
        params={"url": TEST_URL, "timeout": TIMEOUT * 1000},
        timeout=TIMEOUT + 2,
    )
    response.raise_for_status()
    return response.json().get("delay", 99999)

def switch(name):
    response = requests.put(
        f"{API}/proxies/{requests.utils.quote(GROUP, safe='')}",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={"name": name},
        timeout=TIMEOUT,
    )
    response.raise_for_status()

data = get_proxies()
group = data[GROUP]
current = group.get("now")
candidates = [
    name for name in group.get("all", [])
    if name not in {"DIRECT", "REJECT"} and name != GROUP
]

best = None
best_delay = 99999
for name in candidates:
    try:
        delay = measure(name)
        print(name, delay, "ms")
        if delay < best_delay and delay <= MAX_DELAY:
            best, best_delay = name, delay
    except requests.RequestException:
        continue

if best and best != current:
    switch(best)
    print("switched to", best)
else:
    print("keep current node", current)

time.sleep(1)

实际运行时还需要补充状态记录。建议把每次测试的时间、节点名称、延迟、错误原因和切换结果写入日志,并为每个节点维护连续失败计数。例如某节点第一次超时只增加一次失败计数,连续三次失败后才标记为不健康;成功测试后则逐步恢复评分。这样可以避免因为某个测试地址偶尔不可达而误判整条线路。

推荐的切换参数

  • 检测间隔:普通桌面使用可设为 60 至 180 秒,服务器场景根据业务重要性调整。
  • 延迟阈值:不要照搬固定数值,先测出稳定线路的常态范围,再设置明显高于常态的阈值。
  • 连续失败次数:建议至少 2 至 3 次,避免单次网络抖动触发切换。
  • 冷却时间:切换后等待一段时间再重新评估,防止两个节点之间来回震荡。

对长期运行的脚本,最好增加锁机制,保证同一时间只有一个实例执行切换;还要处理客户端重启、配置热更新和策略组不存在等情况。如果脚本检测到 API 无响应,应先等待并重试,而不是立刻把所有节点判为故障。系统服务可以使用 Windows 任务计划程序、Linux 的 systemd timer 或容器的定时任务执行,但运行账户应使用最低必要权限。

第四步:通过连接和日志判断「节点坏了」还是「规则有问题」

自动切换系统最容易犯的错误,是把所有访问失败都归因于节点质量。实际上,策略组配置错误、DNS 解析失败、规则匹配到 DIRECT、浏览器独立启用了 DoH,都会产生类似的超时现象。切换前应该结合连接信息和客户端日志进行判断。

GET /connections 可以查看当前活动连接、目标地址、匹配规则和实际使用的出站代理。若目标请求显示为 DIRECT,而你的预期是走代理,切换节点不会解决问题,应先检查规则顺序和策略组引用。若连接已经匹配到正确节点,但 TCP 建连长期停留在等待状态,再结合延迟测试和错误日志,才更接近节点故障。

日志分析也要区分几个阶段。DNS 阶段失败通常表现为域名无法解析或解析超时;连接阶段失败常见于端口不可达、节点过载或网络阻断;TLS 阶段失败则可能和证书、SNI、时间错误或协议兼容性有关。只看「请求失败」四个字,无法判断应该切换节点、调整 DNS,还是修正配置。

不要让脚本制造故障

延迟探测本身也会消耗节点资源。候选节点很多时,如果每秒并发发起大量测试,可能触发服务端限流,甚至让原本正常的节点变慢。建议限制并发数量、使用稳定但轻量的测试地址,并将测试请求与真实业务请求分开统计。

对于多策略组配置,可以先只自动管理一个主策略组,再观察一段时间的日志和切换记录。确认逻辑稳定后,再决定是否同步切换流媒体、下载或游戏专用策略组。不同业务对线路的要求并不相同:低延迟节点不一定适合大文件下载,解锁某个平台的节点也不一定适合日常网页访问。

第五步:安全加固、部署方式与常见陷阱

external-controller 不是普通的只读状态接口,应按照管理面板来保护。首先,优先监听 127.0.0.1;其次,使用随机密钥并避免把密钥硬编码在公开仓库、截图或分享配置中;再次,脚本输出日志时不要打印完整的 Authorization 请求头。若需要远程管理,建议通过 SSH 隧道、内网 VPN 或带访问控制的反向代理连接,而不是直接将 9090 端口映射到公网。

还要留意配置热更新带来的覆盖问题。很多订阅更新会重新生成代理组,导致策略组名称变化,或者把脚本自定义的控制器设置覆盖掉。可以把固定参数放在 Mixin、覆写配置或独立的本地配置文件中,并在脚本启动时先验证 /version、目标策略组和候选节点是否存在。验证失败时只记录错误并退出,不要对未知路径发起修改请求。

  • 端口冲突:9090 已被其他程序占用时,控制器不会正常监听,可改用未占用的本地端口。
  • 名称编码错误:中文节点名必须进行 URL 编码,策略组名称也不能假设只包含英文字符。
  • API 路径差异:不同内核的连接、配置重载和延迟接口可能略有区别,应以实际返回结果为准。
  • 切换后旧连接仍存在:已有 TCP 或 WebSocket 连接未必会自动迁移到新节点,必要时应在确认影响范围后清理旧连接。
  • 检测地址不可达:测试 URL 被当前网络拦截时,所有节点都会被误判为失败,至少准备两个不同域名进行交叉验证。

建议为自动切换系统设置一个明确的降级策略。例如所有候选节点都失败时保留当前节点,而不是随意切换到第一个节点;控制器暂时不可用时停止修改操作;脚本异常退出时不改变客户端已有配置。对于家用设备,这种保守策略通常比频繁重置连接更稳定;对于业务服务器,则应配合外部监控,在连续失败达到阈值后通知管理员。

一些第三方代理工具只提供简单的手动节点列表,自动化接口不完整,遇到故障时往往只能依赖用户重新打开界面、逐个测速并手动切换,远程运维和日志追踪都比较繁琐。Clash 的 external-controller 能把节点查询、延迟探测、策略组控制和连接诊断统一到标准 HTTP API 中,既方便脚本化,也保留了图形客户端的可视化操作;如果你希望在本文的基础上搭建更稳定的自动恢复流程,不妨免费下载 Clash,立即体验

安全选择机场,轻松管理 Clash 订阅

用规则分流、节点切换和连接日志,降低订阅配置与排错成本。

免费下载 Clash(Windows / macOS)