sing-box 1.12 正式版是一次 DNS 与规则系统的深层重构,而不是常规的 patch 迭代。如果你还在使用旧版 sing-box 内核,升级 1.12 的第一步不是替换二进制文件,而是先打开 dnsroute 两段 JSON 配置逐项排查:有没有 geoip:cngeosite:gfwaddress: "tls://1.1.1.1" 这类写法。这些在 1.12 里要么已经报错,要么正在输出 deprecated 日志,只是还没到强制拒绝的阶段。

DNS server 新格式:address 字符串改成 type 结构体,要改什么?

旧版 DNS server 的典型写法是把协议和地址拼成一行字符串,比如 "address": "tls://1.1.1.1""address": "https://dns.google/dns-query""address": "fakeip"。1.11 之前这种写法是主流也是默认示例。

1.12 把 DNS server 拆成了显式 type 结构体:type: udptype: tlstype: httpstype: fakeiptype: h3 等,地址和服务参数分别写进不同字段。旧写法还能加载,但从 1.12 起启动日志里会出现 deprecated: use type field for DNS server 这类警告。官方的迁移截止版本是 1.14,届时旧写法直接启动失败。

下面是两种写法的对照:

DNS 用途1.11 旧写法1.12 新写法
UDP 上游 DNS"address": "1.1.1.1""type": "udp", "server": "1.1.1.1"
DNS over TLS"address": "tls://1.1.1.1""type": "tls", "server": "1.1.1.1"
DNS over HTTPS"address": "https://dns.google/dns-query""type": "https", "server": "dns.google"
Fake-IP"address": "fakeip""type": "fakeip"
带 tag 的内部分组"tag": "remote-dns", "address": "tls://8.8.8.8""tag": "remote-dns", "type": "tls", "server": "8.8.8.8"

实际场景是你维护了一份给别人用的模板配置,里面写了四五个 DNS server,升级 1.12 后客户端用户反馈 “DNS 查询偶尔很慢”。打开日志一看几十行 deprecated 警告,不是在报错,但每次 DNS 查询都要走兼容转换路径,拖慢了首次解析。

domain_resolver 替代旧 outbound DNS rules:多出站用户最容易漏

这一项改动的影响面比 DNS server 格式更大,因为它改的不是写法而是逻辑层级。

旧逻辑是把 “某个 outbound 用什么 DNS” 写在 dns.rules 里:匹配 outbound == "proxy" 这条 rule,再指定 server。新逻辑把这个决策移到 outbound 自己的拨号配置 dial_fields.domain_resolver,或者全局 route.default_domain_resolver。一次出站拨号触发 DNS 解析时,不再去 dns.rules 里找匹配规则,而是直接看该 outbound 绑定的 resolver tag。

常见踩坑场景:你有一个直连 outbound 和一个代理 outbound,旧配置在 dns.rules 里按 outbound 做 rule_set 匹配。升级 1.12 后直连的 DNS 能解析,代理的 DNS 全部超时——因为 1.12 找不到对应 domain_resolver 时,不会自动 fallback 到旧 rule,而是回到系统默认 DNS,恰好你的代理 outbound 访问不了系统 DNS。

改法分两步:

  1. dns 里定义两个 server:local-dnstype: udp 指本地,remote-dnstype: https 指远程。
  2. 在 outbound 的 dial_fields 里写 "domain_resolver": "remote-dns"。全局默认则在 route 下加 "default_domain_resolver": "local-dns"
旧写法位置 (1.11)新写法位置 (1.12)注意
dns.rules[].outbound 匹配 + serveroutbound 的 dial_fields.domain_resolver每个出站单独声明
无全局默认route.default_domain_resolver兜底所有没声明 domain_resolver 的出站
dns.rules[].domain_strategyoutbound 的 domain_strategy字符串名没变,但层级从 dns 移到 outbound

GeoIP/Geosite 彻底移除:为什么 .srs rule-set 更快?

GeoIP 和 Geosite 从 sing-box 1.8 起就标记为 deprecated,但内核里一直保留兼容,1.11.x 的配置里写 geoip:cn 或者 geosite:geolocation-!cn 仍然能跑。1.12 把兼容代码全部移除了,启动时遇到这两个字段直接报 unknown rule item type,配置拒绝加载。

这件事对性能的影响比很多人预想的大。旧的 geoip.datgeosite.dat 是 V2Ray 年代的文本格式,sing-box 每次启动要解析整个 dat 文件,规则越多、解析越慢。1.12 强制切换到 .srs 二进制 rule-set 文件后,读取方式从全文解析变成了 mmap 内存映射 + 本地缓存,对几百条规则集的配置,启动时间从 3-5 秒缩短到 0.5-1.5 秒是实测可复现的范围。

迁移的完整步骤:

  1. 下载对应 .srs 文件(从 rule-set 官方仓库或自生成),放进配置目录下的 rule-set/ 文件夹。
  2. route.rule_set 里声明本地路径,例如 "type": "local", "path": "rule-set/geoip-cn.srs", "tag": "geoip-cn"
  3. route.rules 里用 rule_set: geoip-cn 替代原来的 geoip:cn
  4. 同理,dns.rules 里也改成 rule_set 引用。
旧字段 (1.11 及之前)新字段 (1.12)文件格式
geoip:cnrule_set: geoip-cn.srs 二进制
geosite:category-ads-allrule_set: geosite-category-ads-all.srs 二进制
geosite:gfwrule_set: geosite-gfw.srs 二进制
geoip:privateip_is_private: true(内建)不再需要外部文件

如果你在路由器或低配 NAS 上跑 sing-box,切到 .srs 之后规则加载的内存占用也有明显下降:旧的 dat 解析需要在堆上分配完整中间结构,.srs 直接 mmap 映射文件,规则匹配时只读被查询的那一段。

1.12 完整变更速览

DNS 和规则之外,1.12 还塞了不少协议层和平台层的改动。下面是按影响面排序的变更表:

类别变更谁需要关注
DNSDNS server 格式重构,旧写法 deprecated所有自维护 JSON 配置用户
DNS/Routedomain_resolver 替代旧 outbound DNS rules多出站配置用户(直连+代理混用)
规则GeoIP/Geosite 彻底移除所有使用 geoip/geosite 的配置
规则.srs rule-set 二进制格式强制所有使用规则集的配置
协议AnyTLS 新协议需要降低 TLS 指纹识别风险的场景
协议ShadowTLS wildcard SNI 支持自建 ShadowTLS 入站的用户
协议NTP 协议 sniffer需要识别 NTP 流量的旁路由场景
平台Apple TUN 性能提升最高 2 倍+iOS/macOS 用户
平台新增 Tailscale endpoint 与 DNS server混合使用 Tailscale 与 sing-box 的用户
平台DERP 服务内建自建 Tailscale DERP 中继节点的用户
平台resolved service (systemd-resolved DBUS)Linux 桌面用户,NetworkManager 接管 DNS
监听bind_interface、routing_mark、reuse_addr多网卡、多路由表环境
加密ECH 迁移到 Go stdlib 实现依赖 ECH 的配置需重新测试兼容性
依赖Go 最低版本升至 1.23,quic-go v0.52.0,gVisor 20250319.0自行编译的用户

从 1.11 升级 1.12,哪些配置项不查会直接报错?

升级不是替换一个二进制文件就完事。以下清单按检出概率从高到低排列,建议先备份当前配置文件和 core 版本号,再逐项过。

检查项怎么看改法
DNS server 是否还在用 address 字符串搜索 "address": + 包含 :// 的行改为 type + server 分离写法
route.rules 里有没有 geoip: / geosite:搜索 geoip:geosite:全部替换为 rule_set 引用 + .srs 文件
dns.rules 里有没有按 outbound 匹配 DNS server搜索 dns.rulesoutbound 条件移到对应 outbound 的 dial_fields.domain_resolver
是否有多出站但没有 default_domain_resolver检查 route"default_domain_resolver": "<tag>"
rule-set 文件是不是 .json/.yaml 文本检查 rule_set 目录下文件后缀替换为 .srs 二进制文件
是否引用了不再存在的旧 route rule action启动日志搜索 deprecatedunknown field对照官方 Migration 改字段名
自编译用户 Go 版本是否 ≥ 1.23go version升级 Go 工具链

建议先在测试 profile 或 staging 环境验证,不要直接覆盖生产配置。命令行用户至少保留 sing-box version 输出和旧 JSON 的副本;SFA 图形客户端用户先导出当前配置文件再操作。

哪些场景可以先不升级?

1.12 不是安全修复版本,不涉及 CVE 修补。如果你的配置没有使用 geoip/geosite、没有多出站混用 DNS 策略、也没有自编译需求,继续用 1.11.x 的生产配置短期内不会出问题。

但官方的 deprecated 移除计划是 1.14 即一刀切:1.12 兼容旧写法(输出警告)、1.13 兼容旧写法(输出警告)、1.14 直接拒绝加载。如果你计划长期使用 sing-box 内核,DNS server 格式和 rule-set 迁移早晚要做,在 1.12 阶段动手比等到 1.14 配置被拒绝时手忙脚乱要好。

相关阅读