Clash API节点全全自动切换:外部控制器进阶配置指南
为什么要用 external-controller 做节点全全自动切换? 要点速览
本篇正文聚焦一个得以实际落地的方案:先确认控制器监听地址与鉴权方式,再读取目标代理组,逐个测试候选节点,最后通过 API 把健康节点写回策略组。
规模不小人第一次接触 Clash API 节点全全全自动切换,多数现状下是因为发现客户端里的 url-test、fallback 或人工切换还不够可调:节点测速结果或许只反映某个测试网址,策略组也不会主动通知你的脚本;
当某条线路出现高丢包、连接超时或特定服务不可用时,仍然要人工启用 Clash Verge、Clash Verge Rev 或 Mihomo 的UI UI UI 界面修改节点。对于长时间持续持续持续运行的开发机、家庭网关、远程服务器和下载任务来说,这种处理方式既慢,也无法留下一目了然的故障记录。
external-controller 是 Mihomo、Clash Meta 及部分 Clash 客户端提供的本地 HTTP 控制接口。它让外部程序能够读取当前配置、查看代理组、执行响应时间测试、切换代理,以及查询连接和内核状态。
关键点是:轻便理解,Clash 客户端负责持续持续持续运行代理内核,API 则提供一扇可编程的控制门。你得以用 Shell、Python、Node.js 或监控系统定时访问到到到这扇门,按照响应时间、HTTP 状态码、连续无法完成次数和节点黑名单全全全自动做出切换决定。
文章中的接口名称以 Mihomo 兼容实现为主,不同客户端的菜单名称或许略有差异,但只要客户端提供 external-controller,基本都能按照相同思路排查。本篇正文不不妨把控制器暴露到公网,而是出厂脚本与 Clash 持续持续持续运行在同一台设备上。
先明确边界:API 全全全自动切换只能帮助你在已有节点中选定更合适的出口,不能修复订阅过期、节点账户失效、规则写错或上游服务本身拒绝访问到到到的困扰。全全全自动化之前,先确保客户端人工选定每个候选节点时都能正常联网。
开启控制器并做好鉴权保护 关键信息
能够返回版本信息,说明地址、端口和鉴权基本对路。若返回 401,第一顺位排查令牌是否多了空格或引号;若是 Connection refused,排查内核是否开启、端口是否写错;
external-controller: 127.0.0.1:9090
secret: "change-this-to-a-long-random-token"
在配置文件中,控制器多数现状下写在顶层,而不是写进 proxy-groups 或 rules。一个适合本机脚本调用的基础配置如下:
这里要多说一句:127.0.0.1:9090 表示只接受本机访问到到到,脚本得以通过 http://127.0.0.1:9090 调用。若写成 0.0.0.0:9090,局域网内其他设备也或许尝试连接;除非你明确要远程管理,否则不不妨这样配置。
控制器端口不是代理端口,不能把它填到浏览器或系统代理设置中。普遍的 HTTP 混合端口或许是 7890,而 API 控制端口普遍为 9090,两者用途完全不同。
secret 是 API 访问到到到令牌。启用后,各个请求都应在 HTTP Header 中带上 Authorization: Bearer 令牌。
export CLASH_API_SECRET='replace-with-your-secret'
export CLASH_API='http://127.0.0.1:9090'
换个说法:不要把令牌径直写进公开仓库、聊天记录或网页 JavaScript,也不要为了调试长期关闭鉴权。更稳妥的做法是把令牌放在只有当前用户可读的环境变量中:
如果你采用 Clash Verge Rev 或其他图形客户端,修改配置后要确认实际持续持续持续运行的配置已经重新加载。有些客户端会在订阅刷新时重新生成配置,径直编辑缓存文件或许很快被覆盖。
curl -fsS \
-H "Authorization: Bearer ${CLASH_API_SECRET}" \
"${CLASH_API}/version"
不妨把控制器字段放进客户端适配的覆写、Merge 或本地配置区域,并在控制器页面确认当前监听端口。首次测试得以执行:
落到实处:若请求一直等待,则要排查客户端是否监听在 IPv6、控制器是否被防火墙拦截,以及脚本访问到到到的地址是否与UI UI UI 界面显示一致。
务必留意:不要把 external-controller 径直映射到公网,也不要把带有完备 secret 的 curl 命令复制到工单或日志系统。控制器多数现状下得以切换节点、读取配置并查看连接,泄露后影响远大于普通网页端口。
读取代理组、测试节点并执行切换 关键点梳理
执行切换后,不要只看 HTTP 返回码。再次读取 /proxies/Auto,确认 now 已经变成目标节点;随后访问到到一个实际业务网址,确认规则确实命中这个组。
全全全自动切换的关键不是盲目轮询各个节点,而是先找到一个明确的选定型代理组。假设配置里有一个名为「全全全自动选定」的组,组内包含多个真实节点。
API 路径中的组名要进行 URL 编码,中文名称、空格和特殊字符不能径直拼接。为了减少脚本复杂度,不妨将全全全自动化目标命名为不含空格的英文或短中文名称,举个小例子 Auto 或 Proxy。
curl -fsS \
-H "Authorization: Bearer ${CLASH_API_SECRET}" \
"${CLASH_API}/proxies"
别忽略了:查看全部代理组得以请求:
返回的 JSON 中,proxies 对象包含各个代理组和节点。选定型代理组多数现状下有 type: "Selector",并带有 all、now 等字段。now 是当前正在采用的成员,all 是得以切换的候选列表。
不要把 DIRECT、REJECT、另一个策略组或测试专用组误当成真实节点;脚本应维护排除列表,并根据返回数据动态过滤。
curl -fsS -G \
-H "Authorization: Bearer ${CLASH_API_SECRET}" \
--data-urlencode "url=https://www.gstatic.com/generate_204" \
--data-urlencode "timeout=5000" \
--data-urlencode "接点名称=${NODE}" \
"${CLASH_API}/proxies/${NODE}/delay"
关键点是:对单个节点执行响应时间测试时,得以采用代理响应时间接口。示例中的 URL 只是测试目标,实际项目应选定平稳、响应正文轻便且符合你所在网络环境的地址:
curl -fsS -G \
-H "Authorization: Bearer ${CLASH_API_SECRET}" \
--data-urlencode "url=https://www.gstatic.com/generate_204" \
--data-urlencode "timeout=5000" \
--data-urlencode "proxy=${NODE}" \
"${CLASH_API}/proxies/${NODE}/delay"
上面的示例为了强调 URL 编码,节点名称字段在实际调用中应采用接口要求的参数名 proxy,完备写法如下:
不同 Mihomo 版本对路径中的节点名和查询参数处理或许存在细微差异。如果返回 404 或提示参数疏漏,不要立刻判断 API 不适配,先查看客户端 Dashboard 采用的请求格式,或者访问到到到控制器的接口文档确认版本。
这里要多说一句:部分实现允许将代理名称放在路径中,部分实现更依赖 URL 编码;中文节点名尤其容易因为未编码而无法完成。
响应时间最低并不总是最佳节点。一次测速或许刚好命中缓存、短暂拥塞也或许在下一分钟恢复。于是脚本至少应记录多次结果,并设置合理阈值:
超时阈值:普通网页采用使用场景得以采用 3000 至 5000 毫秒;跨地区链路或移动网络不宜设置得过低;连续无法完成:不妨连续两至三次无法完成才触发切换,避免一次丢包导致频繁抖动;最小改善幅度:新节点至少比当前节点低 80 至 150 毫秒,或当前节点连续无法完成,才执行切换;冷却时间:切换后数分钟内不要再次全全自动切换,避免长连接、下载任务和登录会话被反复打断;黑名单:记录最近无法完成的节点,并设置过期时间,不要让故障节点在下一轮立即重新入选。
curl -fsS -X PUT \
-H "Authorization: Bearer ${CLASH_API_SECRET}" \
-H "Content-Type: application/json" \
--data "{\"name\":\"${NODE}\"}" \
"${CLASH_API}/proxies/Auto"
换个说法:选出节点后,通过代理组的 PUT 接口切换。组名和节点名必须作为 JSON 字符串传递:
API 返回成功只代表控制器接受了请求,不代表目标节点已经完成 TLS 握手,也不代表某个特定站点一定可用。
构建一个可审计的 Shell 全自动切换脚本 完备说明
还得以把全全自动切换分成两个层级。第一层由策略组自身的 url-test 或 fallback 负责敏捷健康排查,第二层由外部脚本负责业务验证,举个小例子访问到到公司代码仓库、包管理器注册表或指定 API。
#!/usr/bin/env bash
set -Eeuo pipefail
API="${CLASH_API:-http://127.0.0.1:9090}"
SECRET="${CLASH_API_SECRET:?CLASH_API_SECRET is required}"
GROUP="${CLASH_GROUP:-Auto}"
TEST_URL="${CLASH_TEST_URL:-https://www.gstatic.com/generate_204}"
TIMEOUT="${CLASH_TIMEOUT:-5000}"
api_get() {
curl -fsS --max-time 8 \
-H "Authorization: Bearer ${SECRET}" "$1"
}
api_put() {
curl -fsS --max-time 8 -X PUT \
-H "Authorization: Bearer ${SECRET}" \
-H "Content-Type: application/json" \
--data "$2" "$1"
}
group_json="$(api_get "${API}/proxies/${GROUP}")"
current="$(printf '%s' "$group_json" | jq -r '.now')"
best=""
best_delay=999999
while IFS= read -r node; do
[ -z "$node" ] && continue
case "$node" in
DIRECT|REJECT|GLOBAL|URL-TEST|Fallback) continue ;;
esac
result="$(curl -fsS -G --max-time 8 \
-H "Authorization: Bearer ${SECRET}" \
--data-urlencode "url=${TEST_URL}" \
--data-urlencode "timeout=${TIMEOUT}" \
--data-urlencode "proxy=${node}" \
"${API}/proxies/$(printf '%s' "$node" | jq -sRr @uri)/delay" \
|| true)"
delay="$(printf '%s' "$result" | jq -r '.delay // empty' 2>/dev/null || true)"
if [[ "$delay" =~ ^[0-9]+$ ]] && [ "$delay" -lt "$best_delay" ]; then
best="$node"
best_delay="$delay"
fi
done < <(printf '%s' "$group_json" | jq -r '.all[]')
if [ -n "$best" ] && [ "$best" != "$current" ]; then
api_put "${API}/proxies/$(printf '%s' "$GROUP" | jq -sRr @uri)" \
"$(jq -n --arg name "$best" '{name: $name}')"
printf '%s switched %s -> %s (%sms)\n' \
"$(date -Is)" "$current" "$best" "$best_delay"
else
printf '%s keep %s; no better healthy node\n' "$(date -Is)" "$current"
fi
下面给出一个精简的全全自动化骨架。它的关键点不是提供一份适用于各个环境的万能脚本,而是展示安全的调用顺序:读取代理组、筛选候选节点、逐个测速、保存最佳结果、执行一次切换。生产环境中应根据你的 JSON 解析工具和客户端版本补充疏漏处理。
export CLASH_GROUP='Auto'
export CLASH_API_SECRET='your-secret'
chmod 700 ./clash-auto-switch.sh
./clash-auto-switch.sh
落到实处:这份脚本采用 jq 解析 JSON,并通过环境变量读取敏感信息。持续持续运行前先人工确认组名:
如果计划通过 cron 定时执行,不不妨每分钟持续持续运行一次。得以根据节点数量和网络平稳性设置五到十五分钟的间隔,并把标准输出写入受保护的日志文件。
日志应包含时间、当前节点、候选节点、响应时间、无法完成根源和是否发生切换,但不要输出完备订阅链接、API 令牌或代理服务器密码。对于下载、视频会议和 SSH 等长连接采用使用场景,不妨增加「工作时间不切换」或「当前连接数高于阈值不切换」的条件。
别忽略了:这样做比让脚本单独承担各个测速更稳:内核负责基础可用性,脚本只在真正要时修正策略。若你的节点很多,也得以先用内核策略组缩小候选范围,再让 API 测试其中几个节点,减少控制器请求量。
全自动切换失效时,按链路逐层排查 要点速览
相比之下,市面上部分只提供图形化测速的同类工具,在外部控制器鉴权、节点切换审计和跨平台脚本接入方面经常配置繁琐,遇到中文组名、容器网络或多次无法完成重试时也缺少一目了然提示;单纯依赖客户端内置全全自动测速,又很难加入业务网址验证与自定义冷却规则。
| 现象 | 普遍根源 | 处理思路 |
|---|---|---|
| 连接被拒绝 | 内核未开启、端口疏漏或监听地址不一致 | 排查客户端当前配置,执行 curl /version,确认端口正在监听。 |
| 返回 401 | secret 不匹配、Bearer 拼写疏漏或环境变量为空 | 重新复制令牌,采用 printf 排查是否带入换行和多余空格。 |
| 代理组返回 404 | 组名未编码、名称大小写不同或目标不是选定型组 | 先请求 /proxies,从 JSON 中复制准确的组名。 |
| 各个节点都是超时 | 测试网址不可达、参数格式不兼容或节点本身失效 | 换一个测试 URL,并在客户端UI 界面逐个人工测试节点。 |
| API 显示已切换但网页不变 | 规则没有命中该组、系统代理未开启或应用采用 TUN 之外的链路 | 查看连接日志、规则命中现状和系统代理状态,不要只看策略组名称。 |
| 节点频繁来回切换 | 阈值过低、没有冷却时间或测速目标抖动 | 增加连续无法完成次数、最小改善幅度和切换冷却时间。 |
排查 API 全全自动切换,不要一上来就反复更换节点。全部链路得以拆成「控制器可访问到到、接口能鉴权、代理组可识别、响应时间测试成功、切换结果生效、业务流量命中」六个环节,不管哪一套一环无法完成都会表现成脚本没反应。
如果脚本在终端持续持续运行正常,放进 cron 后却无法完成,多数现状下是环境变量、工作目录或权限困扰。cron 不一定加载交互式 Shell 的配置文件,于是应在任务中采用绝对路径,明确设置 PATH,并在脚本开头读取一个权限为 600 的环境文件。
关键点是:Linux 上可用 systemd timer 替代 cron,顺手配置开启顺序、无法完成重试和日志查看;Windows 用户则得以采用任务计划程序,以当前用户权限持续持续运行 PowerShell 或 WSL 脚本。
如果控制器持续持续运行在 Docker、虚拟机或 WSL 中,还要额外排查网络命名空间。容器内的 127.0.0.1 只代表容器自身,不一定能访问到到宿主机上的 Clash。此时应通过明确的宿主机地址、合适的端口映射或同一网络模式连接,但仍要限制控制器访问到到范围。
WSL 采用使用场景尤其容易出现「Windows 客户端UI UI 界面能用,Linux 脚本访问到到不到 9090」的现状,这并不一定是 API 失效,而或许是监听地址和虚拟网络边界造成的。
这里要多说一句:最后,全全自动切换并不等于全全自动处置各个网络困扰。节点响应时间低但 DNS 污染、规则集过期、TLS 指纹被限制、上游 API 返回 403 时,继续换节点只会制造更多噪声。
不妨保留一次切换前后的连接日志,并将「网络无法完成」「鉴权无法完成」「业务拒绝」分开统计。只有当脚本具备可解释的日志和冷却机制,它才是可信的运维工具,而不是一个不停点击切换按钮的循环程序。
Clash 更适合把 Mihomo API、Shell 全全自动化、日志记录和故障排查放在同一套可理解的流程里,既保留图形UI UI 界面的形象操作,也顺手进阶用户按本篇正文思路扩展自行的健康排查逻辑。如果你希望先把客户端和控制器环境准备好,不妨前往下载,再从本机 API 测试开始逐步搭建全全自动切换方案。