升级后旧 JSON 能导入,不代表它能被新 core 启动。很多 GUI 会先保存 profile,再把配置交给 sing-box core;真正的错误会出现在运行日志里。
这篇只处理 3 个版本节点:1.12、1.14、1.16。1.11、1.8 等更早迁移不展开,避免把一次排障变成整份配置重写。
##判断你卡在哪个字段
看日志里的字段名,不要先怀疑客户端坏了。下面这张表能把问题缩小到订阅模板、规则集或 DNS 结构。
| 日志线索或旧字段 | 版本限制 | 更可能原因 | 先改哪里 |
|---|---|---|---|
legacy DNS server、旧 dns.servers 写法 | 1.12 废弃,1.14 移除 | 旧 DNS server 格式还在 profile 里 | dns.servers 与 dns.rules |
geoip、geosite | 1.8 废弃,1.12 移除 | 旧 GeoIP/Geosite 条件没迁到规则集 | route.rule_set 与 route.rules |
rule_set not found | 迁移后常见 | tag 定义和引用不一致 | route.rule_set[].tag |
download_detour warning | 1.14 废弃,计划 1.16 移除 | remote rule_set 仍用旧下载字段 | http_client |
| 订阅导入正常、启动失败 | 常见于 GUI | GUI 保存了旧 JSON,core 拒绝运行 | 用 core 命令校验配置 |
如果你只能看到 GUI 弹窗,打开详细日志。错误里只要出现上表任一字段,就按配置迁移处理。
1.12、1.14、1.16 三个版本限制怎么记?
官方 migration 页面覆盖多个历史版本,deprecated 页面给出字段级废弃和移除提示。排这类问题时,把限制压成下面 3 行最容易记。
| 版本节点 | 对这次迁移的意义 | 你要做的动作 |
|---|---|---|
| 1.12 | 旧 DNS server 格式进入废弃期;GeoIP/Geosite 已到移除限制 | 不再新增旧 DNS 写法;把 geoip/geosite 规则迁到 rule_set |
| 1.14 | legacy DNS server 旧格式被移除;download_detour 开始废弃 | 启动失败先改 DNS;看到 download_detour warning 就排期替换 |
| 1.16 | deprecated 页面标注 download_detour 的计划移除点 | 订阅生成器、模板仓库、远程规则集配置提前改 http_client |
所以很多人从 1.11 或 1.12 直接跳到 1.14 时,会一次看到 2 类错误:DNS 直接阻断启动,规则集下载字段先给 warning。
怎么确认不是 GUI 客户端自己的问题?
把 GUI 里的配置导出成 JSON,然后用 sing-box core 单独检查。不同系统路径不一样,命令结构相同。
sing-box version
sing-box check -c ./config.json
如果 GUI 没有导出按钮,至少在 profile 目录复制一份配置,不要直接改唯一文件。改错后无法回滚,会把 DNS、路由和节点问题混在一起。
还可以用字段搜索先定位旧写法:
grep -n 'download_detour\|geosite\|geoip\|rule_set\|servers' ./config.json
看到 geoip 或 geosite 时,不要只把字段名改成 rule_set。rule_set 需要先定义规则集,再在规则里引用 tag。
legacy DNS server 旧格式怎么迁?
旧配置里常见问题是 DNS server 只有一个地址,或者 server 对象仍使用 1.12 前的旧形态。1.14 后要改成新的 DNS server 结构,并让 DNS rule 引用 server tag。
旧思路通常像这样:
{
"dns": {
"servers": [
"https://dns.example/dns-query"
]
}
}
迁移时先把 server 变成可被引用的对象。下面只展示结构,不代表你的生产 resolver 必须照抄:
{
"dns": {
"servers": [
{
"type": "https",
"tag": "remote-dns",
"server": "dns.example",
"server_port": 443,
"path": "/dns-query"
},
{
"type": "local",
"tag": "local-dns"
}
],
"rules": [
{
"rule_set": ["private-domain"],
"action": "route",
"server": "local-dns"
}
],
"final": "remote-dns"
}
}
改完先验两件事:DNS 分流规则使用 action: "route" 搭配 server,并且 dns.rules[].server 和 dns.final 指向的 tag 都必须在 dns.servers 里存在。不存在就会变成下一轮 tag 报错。
GeoIP/Geosite 到 rule_set 要改哪两层?
GeoIP/Geosite 旧字段不是 1.14 才失效。官方 deprecated 页面标注它们在 1.8.0 废弃、1.12.0 移除;1.14 只是让更多旧配置集中暴露。
旧路由规则可能长这样:
{
"route": {
"rules": [
{
"geosite": ["cn"],
"outbound": "direct"
},
{
"geoip": ["private"],
"outbound": "direct"
}
]
}
}
新结构分两层,在 route.rule_set 定义规则集,再在 route.rules 引用。
{
"route": {
"rule_set": [
{
"type": "remote",
"tag": "geosite-cn",
"format": "binary",
"url": "https://example.com/geosite-cn.srs"
},
{
"type": "remote",
"tag": "geoip-private",
"format": "binary",
"url": "https://example.com/geoip-private.srs"
}
],
"rules": [
{
"rule_set": ["geosite-cn", "geoip-private"],
"outbound": "direct"
}
],
"final": "proxy"
}
}
这里最容易错的是文件格式。Mihomo 的 .mrs、传统 .list、sing-box 的二进制 .srs 不是一回事;format 要和远程文件内容匹配。
DNS rules 里的 rule_set 又怎么处理?
DNS rule 文档里也有 rule_set 条件。意思是:DNS 分流可以引用规则集,但规则集本身仍放在 route.rule_set 里统一定义;真正切换解析服务器时,用 DNS rule action 的 route 动作指向 server tag。
典型结构是:
{
"dns": {
"rules": [
{
"rule_set": ["geosite-cn"],
"action": "route",
"server": "local-dns"
}
],
"final": "remote-dns"
},
"route": {
"rule_set": [
{
"type": "remote",
"tag": "geosite-cn",
"format": "binary",
"url": "https://example.com/geosite-cn.srs"
}
]
}
}
如果日志同时报 DNS server 和 rule_set,先改 DNS server 旧格式,再处理规则集。DNS server 结构不合法时,后面的 rule_set 报错可能只是连带现象。
订阅侧什么时候必须更新?
只改本地文件适合临时救急;只要你的 profile 来自订阅 URL,下次更新还会把旧字段带回来。判断订阅侧是否要改,看 3 个信号。
| 信号 | 本地改配置够不够 | 处理建议 |
|---|---|---|
每次更新后 download_detour 又出现 | 不够 | 改订阅模板或让上游输出新字段 |
| 多台设备同时报 legacy DNS server | 不够 | 订阅生成器仍在下发旧 DNS 格式 |
| 只有一台旧 GUI 报错 | 可能够 | 确认该 GUI 内置 core 版本 |
| 同一订阅有 Clash、Mihomo、sing-box 多种导出 | 看导出类型 | 确认选的是 sing-box profile,不要拿 YAML 转 JSON 硬套 |
多客户端共用订阅时,最怕后台把 Clash/Mihomo 模板和 sing-box 模板混发。需要重新校验订阅导出类型时,可以用兼容 Clash / Singbox / V2Ray 的订阅做对照测试;真正上线的 JSON 仍要按 sing-box 当前文档校验。
download_detour 到 http_client 怎么迁?
download_detour 常出现在 remote rule_set 里,用来指定规则集下载走哪个 outbound。官方 deprecated 页面标注:它在 1.14.0 废弃,使用 http_client 替代,并计划在 1.16.0 移除。当前 rule-set 文档里,http_client 可以写成共享 HTTP client 的 tag,也可以写成内联对象。
旧写法大致是:
{
"route": {
"rule_set": [
{
"type": "remote",
"tag": "geosite-cn",
"format": "binary",
"url": "https://example.com/geosite-cn.srs",
"download_detour": "proxy"
}
]
}
}
迁移时保留 type、tag、format、url,把下载客户端相关设置挪到官方当前文档支持的 http_client。下面用内联对象展示;如果你的配置已经集中定义 HTTP client,也可以在这里填对应 tag。字段细节要以你使用的 1.14 小版本文档为准,别从旧模板里复制半截。
{
"route": {
"rule_set": [
{
"type": "remote",
"tag": "geosite-cn",
"format": "binary",
"url": "https://example.com/geosite-cn.srs",
"http_client": {
"detour": "proxy"
}
}
]
}
}
如果 http_client.detour 指向的 outbound 不存在,下载仍会失败。替换字段后,再查一次 outbounds[].tag。
改完怎么验收?
不要只看 GUI 里按钮变绿。至少做 4 个检查。
sing-box check -c ./config.json
grep -n 'download_detour\|geosite\|geoip' ./config.json
grep -n '"tag"\|"rule_set"\|"server"' ./config.json
验收清单:
sing-box check不再报 legacy DNS server。- 配置里没有旧
geoip、geosite条件。 route.rule_set[].tag与route.rules[].rule_set、dns.rules[].rule_set完全一致。- remote rule_set 下载没有把 HTML、登录页或错误页当成规则文件。
download_detour不再出现在新模板里。- 重启 GUI 后没有被订阅更新覆盖回旧字段。
最后一步一定要重启客户端。只热更新规则集,未必会重新解析 DNS server 结构。