升级后旧 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.serversdns.rules
geoipgeosite1.8 废弃,1.12 移除旧 GeoIP/Geosite 条件没迁到规则集route.rule_setroute.rules
rule_set not found迁移后常见tag 定义和引用不一致route.rule_set[].tag
download_detour warning1.14 废弃,计划 1.16 移除remote rule_set 仍用旧下载字段http_client
订阅导入正常、启动失败常见于 GUIGUI 保存了旧 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.14legacy DNS server 旧格式被移除;download_detour 开始废弃启动失败先改 DNS;看到 download_detour warning 就排期替换
1.16deprecated 页面标注 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

看到 geoipgeosite 时,不要只把字段名改成 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[].serverdns.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"
      }
    ]
  }
}

迁移时保留 typetagformaturl,把下载客户端相关设置挪到官方当前文档支持的 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。
  • 配置里没有旧 geoipgeosite 条件。
  • route.rule_set[].tagroute.rules[].rule_setdns.rules[].rule_set 完全一致。
  • remote rule_set 下载没有把 HTML、登录页或错误页当成规则文件。
  • download_detour 不再出现在新模板里。
  • 重启 GUI 后没有被订阅更新覆盖回旧字段。

最后一步一定要重启客户端。只热更新规则集,未必会重新解析 DNS server 结构。

相关阅读