订阅格式转换教程:Clash ↔ sing-box ↔ Surge ↔ 通用(2026)
客户端报'格式不支持'或导入后节点列表为空,根源通常是订阅格式与客户端不匹配。本文不逐个客户端讲导入,而是把三种转换方案(Sub-Store、subconverter、手动脚本)的适用场景、操作步骤和翻车点一次性讲完。补充入口位置、失败提示和回退动作,重点放在读者能马上检查的页面。
操作步骤速查
确认源订阅是什么格式、目标客户端接受什么格式
在浏览器地址栏粘贴你的订阅链接,回车看返回内容。返回内容以 `proxies:` 或 `mixed-port:` 开头的是 Clash YAML;以 `{` 开头且包含 `"outbounds"` 字段的是 sing-box JSON;以 `[General]` 开头的是 Surge .conf;以一大段 base64 字符串(如 `ss://` 或 `vmess://` 的 base64 编码)开头的是节点列表。同时打开目标客户端的订阅导入界面,查看它支持的格式列表:Clash Verge Rev 支持 Clash YAML,sing-box 支持 sing-box JSON,Shadowrocket 和 v2rayNG 只接受 base64 节点列表,Surge 只认 .conf 格式。
预期结果:你手里拿到的原始返回内容和目标客户端支持的格式之间是否匹配已经明确。如果格式一致,不需要转换,直接导入即可;如果不一致,记下'源格式 → 目标格式',进入下一步选方案。
很多人卡在这一步是因为没在浏览器里打开过订阅链接,直接往客户端里贴。浏览器打开是最快的自检方式——3 秒就能判断是格式问题还是链接本身失效了。
判断转换方案:Sub-Store / subconverter / 手动脚本
根据你的实际情况,参考正文'三种方案怎么选'表格做决定:有多条订阅要合并或频繁切换格式 → Sub-Store;只需要一次格式转换且接受公共实例 → subconverter 公共实例;长期主力使用且在意隐私 → 自建 subconverter 或 Sub-Store CF Workers;只有几个节点临时急用 → 手动改 YAML/JSON。选好方案后,Sub-Store 用户跳转到已发布的 Sub-Store 完整指南,subconverter 用户继续下一步。
预期结果:你已经确定了要用的转换方案,并且知道去哪里操作:Sub-Store → 部署后面板操作;subconverter 公共实例 → 拼 URL;手动 → 写十几行 Python 或手工改 YAML。
不要同时踩两个坑——先只用一个方案跑通一条订阅转换,确认导入客户端正常,再考虑合并订阅或加规则。
用 subconverter 公共实例拼接转换 URL
选一个可用的公共 subconverter 实例(社区清单见 subconverter GitHub README 的'公共实例'节),把原始订阅链接和目标格式参数拼进 API URL。格式:`https://<实例域名>/sub?target=<目标格式>&url=<原始订阅链接(URL编码后)>&filename=<自定义文件名>`。target 常用值:`clash`(Clash YAML)、`singbox`(sing-box JSON)、`surge`(Surge .conf)、`quanx`(Quantumult X)、`v2ray`(V2Ray base64)。粘贴原始订阅链接时,先用在线 URL 编码工具或浏览器地址栏自动编码处理一遍——`?` 会变成 `%3F`,`&` 变成 `%26`,`=` 变成 `%3D`。拼好的链接直接在浏览器打开,确认返回了目标格式的有效文本。
预期结果:浏览器访问拼接后的 URL,页面显示的是目标格式的纯文本内容(Clash YAML 以 `proxies:` 开头;sing-box JSON 是合法 JSON;Surge .conf 以 `[General]` 开头)。这个拼接 URL 本身就可以作为订阅链接直接贴进客户端。
如果返回的不是目标格式而是一堆 HTML 或 error 提示,先检查 target 参数有没有拼错(singbox 不是 sing-box,没有横杠);再检查原始链接的 URL 编码是否完整。
手动转换少量节点(Clash YAML ↔ base64 节点列表)
只有 3-5 个节点需要转且不想部署任何工具时,手动改最快。Clash YAML 转 base64 节点列表:打开 YAML 文件,找到 `proxies:` 区块,对每个节点提取 `server`、`port`、`password`、`cipher`、`type` 字段,拼成 SS URI(`ss://base64(method:password)@server:port#name`)或 VMess URI 后 base64 编码全部行。base64 节点列表转 Clash YAML:先用 `echo 'base64字符串' | base64 -d`(Linux/macOS)解码,得到 URI 格式节点行,手动写入 YAML 的 `proxies:` 数组下,再在文件末尾补上 `proxy-groups` 和 `rules` 区块。`proxy-groups` 至少需要一个 select 组和 MATCH 兜底规则。
预期结果:手动拼出来的 YAML 文件用 `yamllint` 或在线 YAML 校验器确认无语法错误;base64 节点列表粘贴到 v2rayNG 或 Shadowrocket 的'从粘贴板导入'中能正确识别节点。
手动转换最坑的是漏掉 proxy-groups 和 rules。只改完 proxies 数组就开始导入了,结果客户端能显示节点但选不了、或者选了不走代理。记得在 YAML 文件末尾至少加上 `proxy-groups: [{name: Proxy, type: select, proxies: [DIRECT, ...节点列表]}]` 和 `rules: [MATCH, Proxy]`。
把转换后的订阅导入客户端并验证
将转换后生成的链接(Sub-Store 输出的订阅链接 / subconverter 拼接 URL / 手动拼好的文件)导入目标客户端。导入方式因客户端而异:Clash Verge Rev 走 Profiles → From URL;sing-box iOS 走 Profiles → New Profile → 粘贴链接;Shadowrocket 走首页右上角 + → 类型选 Subscribe → 粘贴 URL。导入后切到客户端日志页看有没有 parse error 或 unsupported proxy type 报错。然后在 Proxies / 节点列表页确认节点数量和名称是否与源订阅一致。最后打开系统代理,浏览器访问 `https://api.ipify.org` 看 IP 是否变为节点出口 IP。
预期结果:客户端日志无 parse error 或 invalid config 报错;Proxies 页面节点数量与源订阅一致(偶尔新协议如 Hysteria2 可能丢失 1-2 个节点,属工具兼容性限制);浏览器访问 `api.ipify.org` 显示的 IP 与节点出口 IP 一致。
导入后节点数不对?先别改格式参数,用浏览器直接打开转换后的链接,数一下文本里的节点条目数。转换工具丢节点的情况常见于 Hysteria2 和 TUIC v5,这两种协议 subconverter 支持有延迟。
你从服务商拿到了订阅链接,粘贴到客户端里,弹出来一行红字:“不支持的格式”或”解析失败”。打开订阅链接一看——浏览器返回的是 Clash YAML,但你用的是 v2rayNG,它只认 base64 节点列表。或者反过来:sing-box 要 JSON,服务商只给 Clash YAML。
订阅格式不兼容是导入失败最常被忽略的原因。v2rayNG 不吃 Clash YAML,sing-box 不吃 base64 节点列表,Surge 只认自己的 .conf 格式。解决方案有三种:Sub-Store(Cloudflare Workers 免费部署,有 Web UI)、subconverter(自建或公共实例)、手动脚本(适合少量节点快速改)。 新手选 Sub-Store,老手选 self-hosted subconverter。
你的客户端到底要什么格式
在选转换方案之前,先搞清楚两件事:源订阅是什么格式,目标客户端接受什么格式。下表覆盖了 2026 年主流客户端的订阅格式兼容情况。
| 客户端 | 支持的订阅格式 | 不接受的格式 |
|---|---|---|
| Clash Verge Rev / Mihomo Party | Clash YAML(.yaml) | sing-box JSON、base64 节点列表、Surge .conf |
| sing-box(iOS / Android / 桌面) | sing-box JSON;部分支持 Clash YAML(需 clash_api 模块) | base64 节点列表、Surge .conf |
| Surge(iOS / macOS) | Surge .conf(INI 风格配置文件) | Clash YAML、sing-box JSON、base64 |
| Shadowrocket(iOS) | base64 编码的节点列表、SS / SSR / V2Ray 链接 | Clash YAML、sing-box JSON |
| Quantumult X(iOS) | .conf 格式、base64 节点列表 | 完整 Clash YAML、sing-box JSON |
| Stash(iOS / macOS) | Clash YAML | sing-box JSON、Surge .conf |
| v2rayNG(Android) | base64 节点列表、V2Ray 订阅链接 | Clash YAML、sing-box JSON、Surge .conf |
| NekoBox(Android) | 订阅链接(自定义格式)、手动粘贴 | 完整 Clash YAML、Surge .conf |
| Hiddify(跨平台) | sing-box JSON、V2Ray 订阅链接 | Surge .conf |
用表格对一下你的情况:服务商给了 Clash YAML,但你在 iPhone 上用 Shadowrocket——直接导入必然失败。需要把 Clash YAML 转成 base64 节点列表。如果格式本身就匹配,不需要走转换,直接导入即可。
订阅链接打开后,一眼能判断是什么格式吗
就算是同类格式,不同客户端对字段名、缩进和编码的处理也不一样。在你动手转换之前,用浏览器打开原始订阅链接,看返回内容的开头几行:
proxies:或mixed-port:开头 → Clash YAML{开头,且内部有"outbounds"字段 → sing-box JSON[General]或[Proxy]段落 → Surge .conf- 一大段纯 base64 字符(没有 yaml/json 特征)→ base64 节点列表
如果浏览器打开后返回的是登录页面、404 或空白,说明订阅链接本身已失效——这时候不需要转换,需要重新从服务商获取订阅链接。
Sub-Store 部署一次就能永久用,具体怎么操作
Sub-Store 是目前最完善的跨客户端订阅转换与管理工具(GitHub 9K+ stars),技术栈是 Cloudflare Workers + KV。部署后你得到一个带 Web UI 的面板,把一条或多条订阅 URL 导入,勾选目标输出格式(Clash / sing-box / Surge / Quantumult X / Shadowrocket / Loon / Stash / Egern),它就生成一条目标格式的新订阅链接。
部署方式和完整操作我们已经单独写了一篇指南:
那篇覆盖了 Vercel / Cloudflare Workers / Docker 三种部署方式、Web UI 操作流程、订阅合并和节点过滤。Sub-Store 的转换核心用的是 subconverter 引擎,但多了一层图形化管理面板和 JS 脚本扩展能力。
什么时候选 Sub-Store:手里有多条订阅想合并成一条;经常在不同客户端之间切换,每次都要重新导出不同格式;不想碰命令行和 URL 参数拼接。
subconverter:老手的瑞士军刀
subconverter 是订阅格式转换领域的经典开源工具(GitHub 16K+ stars),支持 20+ 种输入和输出格式。它有两条使用路径:直接用社区维护的公共实例(零部署),或者 Docker 自建(一条命令)。
公共实例:3 分钟上手
公共实例的原理不复杂:把你的原始订阅 URL 和目标格式参数拼进 subconverter 的 HTTP API,浏览器打开这条拼接链接,返回的就是转换后的内容。
拼接格式:
https://<实例域名>/sub?target=<目标格式>&url=<原始订阅URL>&filename=<文件名>
三个核心参数:
- target:目标格式。
clash= Clash YAML;singbox= sing-box JSON;surge= Surge .conf;quanx= Quantumult X;v2ray= V2Ray base64;mixed= 混合格式 - url:原始订阅链接,必须做 URL 编码。
?→%3F,&→%26,=→%3D - filename:输出标识名,部分客户端用这个名字在列表里显示
举个例子:你有一条 Clash 订阅 https://api.example.com/sub?token=abc123&flag=clash,要转成 sing-box JSON:
https://subconverter.example.com/sub?target=singbox&url=https%3A%2F%2Fapi.example.com%2Fsub%3Ftoken%3Dabc123%26flag%3Dclash&filename=mysub
浏览器访问这条拼接后的链接,返回的就是 sing-box JSON。这个拼接链接本身就是一条动态转换订阅——把它贴进 sing-box 客户端的订阅地址栏,每次客户端更新时它都会实时转换源订阅并返回最新内容。
自建:一条 Docker 命令
公共实例有隐私风险:第三方可以看到你的请求,包括订阅 URL 中的 token。主力订阅推荐自建:
docker run -d --restart=always -p 25500:25500 tindy2013/subconverter:latest
部署完成后把上面的公共实例域名换成 http://<你的服务器IP>:25500 就行。完整部署和高级参数(&emoji=true、&udp=true、&append_type=true、&config=<规则集URL>)见我们的另一篇:
什么时候选 subconverter:只需要做格式转换不需要 Web UI;写脚本做批量转换或 CI 自动化;自建后完全掌控转换过程。
什么时候值得到手动改?不动手写脚本怎么做
如果你只有 3-5 个节点要转,不想为这件事部署 Sub-Store 或 subconverter,手动改是最快的。
base64 节点列表 → Clash YAML
先用命令解码 base64:
echo '你的base64字符串' | base64 -d
解码后你会看到 URI 格式的节点行(ss://...、vmess://...、trojan://...)。把这些行放进 YAML 的 proxies: 数组下。然后在文件末尾补上 proxy-groups 和 rules 区块——没有这两块,客户端能显示节点但选不了,或者选了不走代理。最小可用结构如下:
proxies:
- {name: "节点1", type: ss, server: 1.2.3.4, port: 8388, cipher: aes-256-gcm, password: "xxx"}
- {name: "节点2", type: vmess, server: 5.6.7.8, port: 443, uuid: "xxx", alterId: 0, cipher: auto}
proxy-groups:
- name: "Proxy"
type: select
proxies:
- "节点1"
- "节点2"
- DIRECT
rules:
- MATCH,Proxy
Clash YAML → base64 节点列表
提取 proxies: 下每个节点的 server、port、password、cipher 字段,拼成 SS URI:
import yaml, base64
with open("clash_config.yaml") as f:
config = yaml.safe_load(f)
for p in config.get("proxies", []):
if p.get("type") == "ss":
userinfo = base64.b64encode(f"{p['cipher']}:{p['password']}".encode()).decode()
uri = f"ss://{userinfo}@{p['server']}:{p['port']}#{p['name']}"
print(uri)
把输出的 URL 行拼在一起 base64 编码一次,贴进 v2rayNG 或 Shadowrocket 的”从粘贴板导入”。
手动转换的硬伤:规则和策略组会全部丢失。 这也是为什么 Sub-Store 和 subconverter 更推荐——它们能保留规则结构并自动生成 proxy-groups。
转换翻车清单
| 翻车现象 | 原因 | 怎么修 |
|---|---|---|
转换后节点名变成 %E9%A6%99%E6%B8%AF 之类的 URL 编码 | subconverter 默认对中文节点名做 URL 编码,部分客户端不解码直接显示 | subconverter URL 加 &emoji=true;Sub-Store 输出设置里 Node Name Encoding → Raw |
| 转换后的配置里没有 rules 和 proxy-groups | 源订阅本身不含规则,或转换时选了 stripped / no-rules 模式 | Sub-Store 勾选「保留规则」;subconverter 确保 target 不是 clashr,且加 &config=<规则集URL> |
| sing-box 导入转换后的配置报 schema 错误 | target 设成了 clash,输出的是 Clash YAML 而非 sing-box JSON | target 必须设成 singbox(不是 sing-box,没有横杠) |
| 公共实例转换后节点延迟全部超时 | 公共实例从它的网络出口测速,延迟不等于你的本地网络测速 | 自建 subconverter 或用 Sub-Store(在本地浏览器完成转换请求) |
三种方案怎么选
| 你的情况 | 选哪个 | 原因 |
|---|---|---|
| 手里多份订阅,想合并成一份 | Sub-Store | Web UI 拖拽合并,不需手动拼 URL |
| 只有一个客户端,偶尔换个格式 | subconverter 公共实例 | 不用部署,拼接 URL 直接贴客户端 |
| 长期主力使用,在意隐私 | Sub-Store(CF Workers)或自建 subconverter | 数据不经过第三方 |
| 只要几个节点,临时应急 | 手动改 YAML / 写 Python 脚本 | 5 分钟搞定,零部署 |
| 写脚本做自动化批量转换 | subconverter HTTP API | 返回纯文本,天然适合管道操作 |
相关阅读
常见问题
- Sub-Store 和 subconverter 到底用哪个?
- Sub-Store 内部用的就是 subconverter 转换引擎,但多了一层 Web UI、订阅合并和 JS 脚本。需要图形界面管理多条订阅选 Sub-Store;只要轻量 HTTP API 做格式转换选 subconverter。
- 转换后节点名变成乱码或 URL 编码(如 %E9%A6%99%E6%B8%AF)怎么回事?
- subconverter 默认对中文节点名做 URL 编码,部分客户端不会自动解码。在 subconverter URL 里加 `&emoji=true` 参数;Sub-Store 在输出设置里把 Node Name Encoding 选为 Raw。改完重新生成订阅链接再导入。
- 转换后的配置里没有分流规则,怎么办?
- 规则和节点是两套独立的东西。大部分服务商给的订阅链接只含节点不含规则。加规则的方法:Sub-Store 勾选'附加规则集';subconverter 在 URL 加 `&config=<规则集URL>` 参数,例如 `&config=https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini`。
- 公共 subconverter 实例有哪些?安全吗?
- 社区维护的公共实例清单见 subconverter GitHub README(`github.com/tindy2013/subconverter`)。公共实例可能记录请求日志,订阅 URL 中的 token 有暴露风险——主力订阅不建议走公共转换站,只适合临时测试或低敏订阅。对隐私有要求就自建。
- 转换后 Hysteria2 / TUIC 节点为什么丢了?
- subconverter 对 Hysteria2 和 TUIC v5 的支持存在滞后。确认工具版本为最新:Sub-Store 点 Settings → Check Update;subconverter 执行 `docker pull tindy2013/subconverter:latest` 重新拉镜像。更新后仍不支持的协议只能手动添加到配置文件中。
来源与时间
本文最后查看时间:2026-05-29。操作路径会随客户端版本变化,遇到按钮名称不一致时,优先按同义菜单和官方文档查看。