家用 SubConverter-Extended:redir-host、IPv6 与多客户端订阅整理

本文由一次真实的家庭网络部署记录整理而来。文中的公网域名、订阅 token、NAS 绝对路径、公司域名和后端随机路径均已脱敏,请按自己的环境替换。

背景

家里有多台设备需要使用 Clash / Mihomo:路由器上跑 OpenWrt + ShellCrash,电脑上可能还会单独跑 Clash 客户端。过去每台客户端各自维护订阅和规则,时间久了以后很容易出现几类问题:

  • 不同客户端规则不一致,排障时很难确认到底命中了哪套策略。
  • 开发场景不喜欢 fake-ip,因为 DNS 查询结果会变成虚拟地址,容易误判服务真实连通性。
  • IPv6 开启以后,国内 IPv6、海外 IPv6、内网 IPv6 的处理逻辑容易混在一起。
  • 企业 VPN / aTrust 这类工具和本机 Clash 共存时,可能会遇到 TUN、fake-ip 网段或进程分流冲突。

这次的目标是把 NAS 上的 SubConverter-Extended 做成统一配置中心:客户端只订阅一个转换后的地址,真正的基础配置、规则碎片、节点聚合都在服务端维护。

最终架构

整体拆成三层:

原始机场订阅 / 多个订阅源
  -> Sub-Store:聚合、过滤、输出固定 share 地址
  -> SubConverter-Extended:生成 Clash / Mihomo 配置
  -> OpenWrt / ShellCrash / 桌面 Clash 客户端

服务上保留两个 SubConverter-Extended 实例:

home 实例
  用于 OpenWrt / ShellCrash
  redir-host
  IPv6 开启
  内网和国内 IPv6 优先直连
​
laptop / work 实例
  用于本机 Clash + 企业 VPN 共存
  fake-ip
  避开企业 VPN 常用网段
  额外加入企业 VPN 可视化策略组

示例网络拓扑如下:

主网关
  10.0.0.1/24
​
旁路由
  10.0.0.3/24
  OpenWrt + ShellCrash + SmartDNS + Mihomo
​
NAS
  10.0.2.1/24
  Sub-Store + SubConverter-Extended
​
客户端
  DNS -> 10.0.0.3

DNS 链路可以理解为:

客户端
  -> SmartDNS
  -> Mihomo DNS
  -> ShellCrash 覆写后的加密 DNS 上游

为什么家用场景选择 redir-host

家用路由器上的 Mihomo 使用 redir-host

ipv6: true
​
dns:
  enable: true
  ipv6: true
  enhanced-mode: redir-host

主要原因是开发和内网服务调试更直观。fake-ip 的优点是适合代理分流和减少 DNS 污染影响,但它会让客户端看到类似 198.18.x.x 的虚拟地址。对日常使用这通常没问题,但如果经常调试内网服务、容器服务、域名解析、IPv6 连通性,虚拟地址会干扰判断。

在路由器统一接管的场景下,redir-host 加上清晰的规则顺序更容易维护。

IPv6 的处理逻辑

这套配置没有简单地把所有 IPv6 都直连,也没有粗暴地全部代理,而是拆成三类。

第一类是本地 IPv6,固定直连:

ruleset=DIRECT,[]IP-CIDR6,::1/128,no-resolve
ruleset=DIRECT,[]IP-CIDR6,fc00::/7,no-resolve
ruleset=DIRECT,[]IP-CIDR6,fe80::/10,no-resolve
ruleset=DIRECT,[]IP-CIDR6,ff00::/8,no-resolve

第二类是国内 IPv6,使用规则集直连:

ruleset=🎯 全球直连,https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/ChinaIpV6.list

第三类是剩余公网 IPv6,交给一个可以手动切换的策略组:

ruleset=🌐 IPv6策略,[]IP-CIDR6,2000::/3,no-resolve

2000::/3 是全球单播 IPv6 范围。关键点在于规则顺序:国内 IPv6 列表必须放在 2000::/3 之前,这样国内 IPv6 会先命中直连,剩下未命中的公网 IPv6 才进入 🌐 IPv6策略

策略组可以这样设计:

🌐 IPv6策略
  -> 🌐 IPv6自动
  -> DIRECT
  -> 🚀 节点选择

🌐 IPv6自动
  使用 IPv6-only 探针 URL 测试节点可用性

探针建议使用只配置 AAAA、不配置 A 记录的域名,例如:

http://ipv6-probe.example.com/generate_204

部署后可以用下面的方式验证:

dig A ipv6-probe.example.com
dig AAAA ipv6-probe.example.com
curl -6 http://ipv6-probe.example.com/generate_204
curl -4 http://ipv6-probe.example.com/generate_204

期望结果是:AAAA 有结果,A 无结果,curl -6 返回 204,curl -4 失败或无法解析。

内网直连不要只写主机地址

如果 NAS、旁路由、主网关分布在多个内网网段,建议按网段写直连,而不是只写某几个 /32 主机地址。

示例:

ruleset=DIRECT,[]IP-CIDR,10.0.0.0/24,no-resolve
ruleset=DIRECT,[]IP-CIDR,10.0.2.0/24,no-resolve

这样访问 NAS 服务、Docker 暴露端口、旁路由管理页、内网 DNS 和其他局域网服务时,不会因为漏掉某个 IP 而被错误送进代理链路。

基于 ACL4SSR Full MultiMode 做母版

自维护大段分组很费时间,所以这次直接使用 ACL4SSR 官方的 Full_MultiMode 作为母版:

https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online_Full_MultiMode.ini

它已经包含常用策略组,例如:

💬 Ai平台
🇭🇰 香港节点
🇨🇳 台湾节点
🇸🇬 狮城节点
🇯🇵 日本节点
🇺🇲 美国节点
🇰🇷 韩国节点
🔯 故障转移
🔮 负载均衡
📹 油管视频
🎥 奈飞视频
Ⓜ️ 微软Bing
Ⓜ️ 微软云盘
🎮 游戏平台

AI 服务需要指定可用地区时,直接在客户端把 💬 Ai平台 切到对应地区节点组即可,不需要另写一整套 AI 分流规则。

Docker Compose 的组织方式

SubConverter-Extended 不建议直接把整个 /base 目录挂载进去。更稳妥的方式是只挂载自己改过的几个文件,避免覆盖镜像自带模板、规则和资源。

示例:

services:
  subconverter-home:
    image: aethersailor/subconverter-extended:latest
    container_name: subconverter-home
    ports:
      - "25500:25500/tcp"
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
    volumes:
      - "/srv/docker/subconverter/base/pref.toml:/base/pref.toml:ro"
      - "/srv/docker/subconverter/base/config/home-redir-ipv6.ini:/base/config/home-redir-ipv6.ini:ro"
      - "/srv/docker/subconverter/base/base/home-redir-ipv6.yaml:/base/base/home-redir-ipv6.yaml:ro"
​
  subconverter-work:
    image: aethersailor/subconverter-extended:latest
    container_name: subconverter-work
    ports:
      - "25501:25500/tcp"
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
    volumes:
      - "/srv/docker/subconverter/work/pref.toml:/base/pref.toml:ro"
      - "/srv/docker/subconverter/base/config/work-vpn.ini:/base/config/work-vpn.ini:ro"
      - "/srv/docker/subconverter/base/base/work-vpn.yaml:/base/base/work-vpn.yaml:ro"

两个实例通过不同的 pref.toml 指向不同默认配置:

default_external_config = "config/home-redir-ipv6.ini"
profile = "public"

工作场景实例:

default_external_config = "config/work-vpn.ini"
managed_config_prefix = "http://127.0.0.1:25501"
profile = "public"

这里继续保持 profile = "public",不通过请求参数暴露任意 config= 文件读取能力。不同场景靠不同实例的默认配置区分。

用 Sub-Store 管理原始订阅

Sub-Store 用来管理多个原始订阅、聚合、过滤,并输出一个固定 share 地址。它不替代 SubConverter,而是负责把节点源整理好,再交给 SubConverter 生成最终配置。

示例:

services:
  sub-store:
    image: xream/sub-store:latest
    container_name: sub-store
    ports:
      - "3001:3001/tcp"
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      NODE_OPTIONS: "--dns-result-order=ipv4first"
      SUB_STORE_FRONTEND_BACKEND_PATH: "/<RANDOM_BACKEND_PATH>"
      SUB_STORE_DATA_BASE_PATH: "/opt/app/data"
    dns:
      - 223.5.5.5
      - 119.29.29.29
      - 1.1.1.1
    volumes:
      - "/srv/docker/sub-store/data:/opt/app/data"

这里给 Sub-Store 单独指定 DNS,是为了避免旁路由或 ShellCrash 关闭时,NAS 的系统 DNS 指向不可用内网地址,导致 Sub-Store 无法解析订阅域名。

Sub-Store 会保存原始订阅数据。如果要公网反代,至少要做到:

  • 后台和 API 不直接暴露公网。
  • share 链路只开放只读路径,例如 /share/
  • token 不写进公开文章、截图或仓库。
  • 反代入口加 Basic Auth、访问控制或只允许 VPN 访问。

provider URL 必须让最终客户端能访问

这是最容易踩坑的一点。

SubConverter 生成的最终 Clash / Mihomo 配置里会包含 proxy-providers.url。这个 URL 不是 SubConverter 自己拉取,而是最终客户端拉取。

所以,如果 OpenWrt / Mihomo 客户端不在 Docker 网络里,就不能写:

http://sub-store:3001/share/col/<COLLECTION>?token=<TOKEN>

应该写成客户端能访问的地址,例如内网:

http://10.0.2.1:3001/share/col/<COLLECTION>?token=<SUB_STORE_SHARE_TOKEN>

如果是公网笔记本,则要写公网只读 share 入口:

https://substore-share.example.com/share/col/<COLLECTION>?token=<SUB_STORE_SHARE_TOKEN>

这一点和 Docker Compose 内部服务名无关。服务名只对容器互访有效,对最终的 OpenWrt、ShellCrash、Clash 客户端没有意义。

给客户端准备短订阅地址

长订阅地址通常包含 targetfilenameurlexclude 等参数,不适合手动维护。可以在 SubConverter 里配置短路径别名,把这些参数固化进去。

最终客户端只需要使用:

http://10.0.2.1:25500/HomeClash
https://sub.example.com/HomeClash
https://sub-work.example.com/HomeClash

短路径内部再指向真实转换参数:

/sub?target=clash&filename=HomeClash&url=<ENCODED_PROVIDER_URL>&exclude=<ENCODED_EXCLUDE_REGEX>

这样后续更换原始订阅、过滤伪节点、调整输出文件名,都可以在服务端完成,客户端无需改配置。

企业 VPN / aTrust 共存场景

路由器场景通常不需要专门处理 aTrust 进程,因为路由器看不到电脑上的进程名。家用侧更重要的是 redir-host、IPv6、内网直连和 DNS 链路。

但如果办公笔记本本机同时运行 aTrust 和 Clash / Mihomo,就建议单独准备一套配置。示例:

dns:
  enhanced-mode: fake-ip
  fake-ip-range: 198.19.0.1/16

tun:
  route-exclude-address:
    - 198.18.0.0/16

这里避开 198.18.0.0/16,避免和企业 VPN / TUN 常见保留网段冲突。

规则上可以加一个可视化策略组:

- PROCESS-NAME,aTrust,🏢 企业VPN
- PROCESS-NAME,aTrustAgent,🏢 企业VPN
- PROCESS-NAME,aTrustXtunnel,🏢 企业VPN
- DOMAIN-SUFFIX,corp.example.com,🏢 企业VPN
- IP-CIDR,198.18.0.0/16,🏢 企业VPN,no-resolve

🏢 企业VPN 默认保持 DIRECT,同时保留 节点选择手动切换 作为排障入口。正常情况下,企业业务链路不应该被代理节点接管。

验证清单

部署后建议先用临时测试节点访问 SubConverter,确认生成的 YAML 是否符合预期:

http://127.0.0.1:25500/sub?target=clash&url=<ENCODED_TEST_NODE>

家用配置重点检查:

ipv6: true
​
dns:
  ipv6: true
  enhanced-mode: redir-host
​
tun:
  route-exclude-address:
    - 10.0.0.0/24
    - 10.0.2.0/24

规则重点检查:

- IP-CIDR,10.0.0.0/24,DIRECT,no-resolve
- IP-CIDR,10.0.2.0/24,DIRECT,no-resolve
- RULE-SET,ChinaIpV6 (IP-CIDR),🎯 全球直连,no-resolve
- IP-CIDR6,2000::/3,🌐 IPv6策略,no-resolve

工作配置重点检查:

dns:
  enhanced-mode: fake-ip
  fake-ip-range: 198.19.0.1/16
​
tun:
  route-exclude-address:
    - 198.18.0.0/16
​
proxy-groups:
  - name: 🏢 企业VPN
  - name: 💬 Ai平台

Sub-Store 检查:

http://127.0.0.1:3001/                                  -> 200 OK
http://127.0.0.1:3001/<RANDOM_BACKEND_PATH>/api/utils/env -> 200 OK
http://10.0.2.1:3001/share/col/<COLLECTION>?token=<TOKEN> -> 可返回节点内容

短路径检查:

http://127.0.0.1:25500/HomeClash       -> 302 -> 200 OK
http://127.0.0.1:25501/HomeClash       -> 302 -> 200 OK
https://sub.example.com/HomeClash      -> 302 -> 200 OK
https://sub-work.example.com/HomeClash -> 302 -> 200 OK

日常维护

规则调整优先改规则碎片:

home-redir-ipv6.ini
work-vpn.ini

DNS、TUN、Mihomo 基础字段优先改 base YAML:

home-redir-ipv6.yaml
work-vpn.yaml

修改挂载文件后重启对应容器:

docker restart subconverter-home
docker restart subconverter-work
docker restart sub-store

升级或大改前建议备份:

docker-compose.yml.bak-YYYYMMDD-HHMMSS
pref.toml.bak-YYYYMMDD-HHMMSS

回滚时恢复备份文件后重新启动服务即可。

这次部署留下的几个经验

第一,redir-host 仍然很适合家用路由器场景,尤其是你需要频繁调试内网和真实 DNS 结果时。

第二,IPv6 不建议只用“全局直连”或“全局代理”二选一。把本地 IPv6、国内 IPv6、剩余公网 IPv6 分开处理,可维护性更好。

第三,Sub-Store 和 SubConverter 的职责要分清。Sub-Store 管订阅源和节点聚合,SubConverter 管规则和最终配置生成。

第四,proxy-providers.url 必须站在最终客户端视角填写。Docker 内部服务名能在容器里访问,不代表 OpenWrt 或公网笔记本能访问。

第五,公网反代 Sub-Store 要非常谨慎。原始订阅、share token、后端 API 路径都不应该直接暴露。

第六,企业 VPN 共存场景最好单独开一套 SubConverter 实例。不要为了兼容一台办公笔记本,把家用路由器配置复杂化。

最终,这套方案把“每台客户端各写一份规则”收敛成了“服务端统一生成配置”。家用设备使用稳定的 redir-host + IPv6 方案,办公笔记本使用独立的 VPN 兼容方案,后续维护时只需要改 NAS 上的几份挂载文件和 Sub-Store 聚合配置。


本站由 DazeCake 使用 Stellar 创建。