前言:让节点切换从手动变成自动
在日常使用 Clash 或 Mihomo 时,节点质量会随着时间、线路拥塞和出口服务状态不断变化。早上延迟只有 80ms 的节点,到了晚上可能已经丢包严重;某个地区的服务器也可能临时维护,导致网页加载缓慢、视频缓冲或连接直接中断。单纯依靠客户端界面手动切换,既耗时,也很难在故障发生时及时处理。
外部控制器(External Controller)提供了一种更灵活的管理方式。Clash 内核会在本机监听一个 HTTP API,外部脚本、监控程序或自定义面板可以通过 API 查询代理组、测试节点延迟、切换当前代理,并根据检测结果执行故障转移。本文以 Mihomo 兼容的 Clash 配置为例,构建一个实用的自动化方案:先安全开启 API,再读取代理组和节点状态,最后使用 Shell 与 Python 完成延迟检测、自动选优和定时切换。
适用场景
适合已经能够正常运行 Clash Verge、Clash Verge Rev、Clash for Windows 或 Mihomo,并希望进行脚本化管理的用户。本文示例默认 API 运行在本机,不建议直接暴露到公网。
1开启外部控制器并做好认证
外部控制器的核心配置通常位于 YAML 文件的顶层。最关键的两个字段是 external-controller 与 secret。前者决定 API 的监听地址和端口,后者用于 Bearer Token 认证。推荐只监听 127.0.0.1,这样只有当前电脑上的程序可以访问 API,局域网中的其他设备无法直接控制你的 Clash。
修改配置后,需要在客户端中重新载入配置或重启内核。不同 GUI 的菜单名称可能略有区别,但一般可以在“设置”“内核设置”“配置文件”或“覆写”区域找到外部控制器选项。如果客户端已经自动生成了 external-controller,请不要同时配置两个监听端口,否则脚本可能连到了错误的实例。
先验证认证和连通性
API 请求需要把密钥放在 Authorization 请求头中,格式为 Bearer 密钥。可以先请求版本接口,确认端口、密钥和内核都正常:
如果返回包含 version、meta 或类似字段的 JSON,说明连接成功。若出现 401 Unauthorized,通常是密钥不一致、Bearer 拼写错误,或者客户端保存的配置并不是当前正在运行的配置。若出现连接被拒绝,则应检查内核是否启动、端口是否被其他程序占用,以及是否误写成了 127.0.0.1:9090/ 这类带路径的地址。
不要暴露管理接口
外部控制器不仅可以查看节点,还可以切换代理、修改运行状态,部分内核还提供配置和连接管理接口。除非你非常清楚防火墙、TLS 和访问控制的配置,否则不要监听在 0.0.0.0,也不要把带有密钥的 API 地址发布到网页或公共代码仓库。
2代理组接口:读取状态、测试延迟与切换节点
自动切换并不是直接对所有节点进行随机选择,而是围绕一个代理组完成。常见的代理组类型包括手动选择组、url-test 自动测速组、故障转移组和负载均衡组。外部脚本最容易控制的是手动选择组:脚本读取该组的成员,逐一测试延迟,然后向组接口发送新的当前代理名称。
读取代理组与当前节点
请求 /proxies 可以获得当前内核识别到的所有代理和代理组。为了只查看指定的策略组,可以使用 URL 编码后的组名访问,例如组名为 Proxy:
返回结果中的 now 表示当前选中的节点,all 通常表示该策略组可选择的成员。不同内核版本返回字段可能略有差异,因此脚本不要假定每个成员都是物理节点;一个代理组也可能嵌套在另一个代理组中。建议先过滤出名称位于目标节点集合中的项目,再执行延迟测试。
调用延迟测试接口
延迟测试接口一般采用以下形式,其中 NAME 是节点名称,url 是测试地址,timeout 是超时时间:
成功时通常会返回类似 {"delay":123} 的 JSON。需要注意,延迟值只反映一次 HTTP 测试,并不等于真实下载速度、视频稳定性或所有网站的访问质量。测试地址应选择响应稳定、体积很小的目标;如果目标本身被网络环境拦截,所有节点都会得到超时结果,脚本就会错误地认为线路全部失效。
切换策略组当前节点
完成选择后,使用 PUT 请求向代理组接口提交 JSON。下面的示例把 Proxy 组切换到名为 日本节点 的成员:
节点名称必须与 API 返回的名称完全一致,包括空格、地区标记和特殊符号。切换后可以再次请求 /proxies/Proxy,确认 now 已经改变。部分客户端会在界面上短暂显示切换状态,这是正常现象;如果组类型本身由自动策略接管,手动切换可能很快又被内核的自动逻辑覆盖。
3动手实践:用 Python 构建健康检查与自动切换
下面的脚本实现一个保守的自动切换流程:读取指定代理组,遍历组成员并测试延迟,忽略测试失败的节点,选择低于阈值且延迟最小的节点;只有当新节点与当前节点不同,并且新节点确实通过测试时,才执行切换。这样可以避免每次运行脚本都重复切换,减少连接被频繁重置的问题。
将下列内容保存为 clash_switch.py。请根据自己的策略组名称修改 GROUP,并通过环境变量提供密钥:
首次运行前安装依赖并设置环境变量:
这个示例没有把“最快”作为唯一标准。实际环境中,延迟低于 800ms 并不代表线路一定稳定,因此还可以增加连续失败次数、最小切换间隔、节点地区白名单和冷却时间。例如最近五分钟已经切换过一次,就暂时不再切换;连续两次测试都失败后,才把当前节点标记为故障。对于视频、会议或下载任务,稳定性通常比瞬时延迟更重要。
Shell 故障转移方案
如果你只需要在当前节点不可用时切换到备用节点,可以使用更轻量的 Shell 脚本。它先测试当前节点的延迟;当请求失败或超过阈值时,再切换到预先指定的备用节点:
Shell 方案依赖 curl、Python 的 URL 编码功能和 JSON 解析,适合 Linux、macOS 或安装了相关工具的 Windows 环境。若节点名称来自不可信输入,不要直接拼接到 Shell 命令中;生产环境应使用 Python 的请求库,或者对名称进行严格转义,避免特殊字符导致命令执行异常。
4定时执行、故障转移与参数调优
自动化脚本真正投入使用时,最重要的不是“多久测一次”,而是避免过度测试和频繁切换。每次延迟测试都会产生连接请求,节点数量较多时可能增加本机和远端服务的负担。通常可以将健康检查间隔设置为 5 至 15 分钟;对于会议、直播等对稳定性敏感的场景,可以在任务开始前主动运行一次,而不是全天高频轮询。
使用定时任务运行
Linux 或 macOS 可以通过 cron 每十分钟执行一次:
密钥直接写在 crontab 中虽然方便,但会出现在进程管理和配置备份中。更安全的做法是把环境变量写入权限为仅当前用户可读的文件,脚本启动时读取该文件;同时限制日志内容,不要打印完整的 Authorization 请求头。Windows 用户可以使用“任务计划程序”,设置为登录后运行,并让任务以固定间隔启动。
推荐的筛选规则
- 延迟阈值:先设置 500 至 800ms,观察真实使用效果后再调整。阈值过低会让脚本频繁判定无可用节点。
- 失败重试:单次超时不应立即切换,建议连续两次或三次失败后再执行故障转移。
- 切换冷却:切换后至少等待数分钟,避免多个脚本同时运行造成来回跳转。
- 节点白名单:只测试自己信任的地区或线路,排除“剩余流量”“过期”“维护中”等名称。
- 测速地址:准备两个或三个稳定的测试 URL,必要时轮换使用,避免单一目标故障造成误判。
推荐运行逻辑
先检测当前节点,再检测候选节点;只有候选节点明显更好,或当前节点连续失败,才执行切换。切换后记录时间、节点名称、延迟和失败原因,出现问题时才能快速回滚。
常见问题解答
请求 API 时返回 401,应该怎么处理?
首先确认请求头格式是 Authorization: Bearer 你的密钥,Bearer 与密钥之间必须有空格。然后检查脚本连接的端口是否与正在运行的 Clash 内核一致。部分客户端会在切换配置后覆盖外部控制器设置,建议重新打开当前配置确认 external-controller 和 secret。
所有节点测速都超时,是节点全部失效了吗?
不一定。测试 URL 可能在当前网络环境中不可达,或者 URL 编码、节点名称编码存在问题。先用浏览器或 curl 单独验证测试地址,再检查接口返回的 HTTP 状态码。也可以更换一个稳定的轻量地址,并适当提高 timeout,但不要无限延长超时时间,否则脚本会长时间阻塞。
为什么脚本切换后,客户端又自动换回原节点?
最常见原因是代理组本身属于 url-test、故障转移或负载均衡类型,内核会按照自己的策略重新计算节点。此时应确认组类型和自动更新间隔;如果需要完全由脚本控制,可以建立一个手动选择组,并让脚本负责检测与切换。
可以把外部控制器开放给局域网设备吗?
技术上可以,但不建议直接监听公网或无保护地监听局域网。若确实需要远程管理,应使用强随机密钥、系统防火墙白名单、VPN 或安全反向代理,并限制可访问的 IP 范围。外部控制器拥有控制代理的权限,安全级别应按照管理接口而不是普通状态查询接口来对待。
通过 API 管理节点的价值,不只是节省几次点击,而是把“发现故障、评估线路、执行切换、记录结果”变成可重复的流程。建议先在本机手动运行脚本,确认 API 返回和节点名称都正确,再加入定时任务;当逻辑稳定后,再逐步增加多测试地址、失败重试、通知和日志保留功能。