DSH-2Xray:把 xray-core 接到 DSH 进程内做全局流量接管

前言

DSH 本身是 HTTP(S) 出口,但智能体在运行时常需要更强的出口策略:切换节点、按域名分流、走固定的 Xray 配置。常规做法是在系统层面配代理环境变量,或者把整个 DSH 的请求单独接出去。前者影响面大、依赖环境;后者容易漏掉 web_fetch 这类只问代理策略层的调用,导致「模型 API 进了代理、网页抓取还直连」的分裂。

下面介绍 TwinsEarth 维护的 DSH 插件 @twinsearth/dsh-2xray(仓库 TwinsEarth/DSH-2Xray)。它定位为 Host-only bundle,在 DSH 进程内承担 xray-core 的启动守护和流量接管,不需要额外构建。

这是什么

插件同时扮演两个角色:xray-core 客户端的进程管理者,以及 DSH 进程内 HTTP(S) 流量的路由者。它生成 xray-core 客户端配置,启动并守护 xray 子进程;在 xray 本地入站确认可用后,把 DSH 进程的全局 HTTP(S) 出口接到该入站;可选地通过零依赖 gRPC 控制面做多节点切换与流量统计。

维护者:TwinsEarth。包名 @twinsearth/dsh-2xray,当前版本 0.8.0,许可证 MIT,要求 Node >= 24.9.0。0.8.0 适配 DSH 0.2.2-rc.1,DSH 0.2.1 及以前需使用 0.7.0。除控制面外无运行时依赖,是一个 Host-only bundle。

核心功能

接入方式上,插件调用 @deepseek-ai/dsh-http-proxy 的 installProxyFromEnvironment(),而不是自己裸装 setGlobalDispatcher()。原因是 DSH 在第一个插件挂载前就已经安装了策略 dispatcher,web_fetch 只询问 proxyRouteFor(),裸装会破坏出口的一致性。

启动与接管遵循固定顺序:写配置 → 起进程 → TCP 就绪 → 204 功能探测 → 接管 dispatcher。只有探测通过后才会接管,避免 dispatcher 指向尚未监听的端口导致整体 ECONNREFUSED。停止时先摘路由,再 terminate,最后等退出。

端口策略是固定端口 + 占用即失败,不做静默换端口。换端口后 DSH 还指向旧端口,表现为持续连接失败,用户无法判断原因。

子进程优先使用 ctx.subprocess,它在 Windows 上是带 KILL_ON_JOB_CLOSE 的 Job Object,可以避免 Electron 关闭后遗留孤儿 xray 占住端口。若没有 Job Object,进程被强杀时 cordis dispose 可能不会执行。

多节点场景下,插件为每个节点生成一个 outbound 和一个 balancer,切换节点只改 RoutingService.OverrideBalancerTarget,进程、入站、dispatcher 都不动。控制面用 node:http2 + 手写 protobuf 实现,不引入 @grpc/grpc-js,目的是减少每个 profile 的依赖和供应链面。

重启策略只针对意外崩溃:退出码 23(配置错)不重启,端口占用不重启,上游不可达也不重启,因为进程本身是健康的。

安装与启用

插件是 Host-only bundle,无需构建。安装命令由插件管理器负责,不提供命令行插件添加形式。

npm i @twinsearth/dsh-2xray

安装后由插件管理器启用;或者在 DSH 插件页选择「从目录安装」,指向本地 Bund​le 目录,例如 E:\GPT\dsh-2xray。

接着需要把 xray 可执行文件放到下面任一位置,解析优先级从高到低:

1. 插件自己的 bin/xray(.exe)(随 bundle 分发时使用)
2. 配置字段 binary.path
3. 环境变量 DSH_XRAY_BIN
4. <DSH_HOME>\xray-proxy\bin\xray.exe(DSH_HOME 默认 %USERPROFILE%\.dsh)
5. 放进 PATH

第三步是编辑 profile 的 cordis.patch.yml(或 bundle 默认配置),填入 server.* 或 nodes[],把 enabled 改成 true,然后重启 profile。bundle 自带配置默认 enabled: false,避免安装即报错。需要留意的是,bundle 的 cordis.patch.yml 是整块配置,profile 层覆盖时必须重述要保留的字段;注册行的 name 必须等于包名 @twinsearth/dsh-2xray,否则 patch 会按「name mismatch」跳过。

单节点配置示例:

- id: xray-proxy
  name: '@twinsearth/dsh-2xray'
  config:
    enabled: true
    server:
      address: example.com
      port: 443
      uuid: 00000000-0000-0000-0000-000000000000
      flow: xtls-rprx-vision
      serverName: www.example.com
      password: REPLACE_WITH_43_CHAR_BASE64URL_X25519_PUBLIC_KEY
      shortId: ''
      fingerprint: chrome
      spiderX: /
    inbound:
      protocol: http
      host: 127.0.0.1
      port: 20808
    takeover: auto

多节点配置示例:

- id: xray-proxy
  name: '@twinsearth/dsh-2xray'
  config:
    enabled: true
    activeNode: hk-01
    nodes:
      - id: hk-01
        address: hk.example.com
        port: 443
        uuid: 11111111-2222-4333-8444-555555555555
        flow: xtls-rprx-vision
        serverName: www.example.com
        password: REPLACE_WITH_43_CHAR_BASE64URL_X25519_PUBLIC_KEY
        shortId: ''
      - id: jp-01
        address: jp.example.com
        port: 443
        uuid: 11111111-2222-4333-8444-555555555555
        flow: xtls-rprx-vision
        serverName: www.example.com
        password: REPLACE_WITH_43_CHAR_BASE64URL_X25519_PUBLIC_KEY
        shortId: ''
    control:
      enabled: true
      port: 10085
      stats: true

nodes[] 与 server.* 二选一,每个节点需要 id/tag 以及 server.* 各字段。activeNode 指定启动时钉住的 node id 或 outbound tag。control.enabled 为 true 时才会开 gRPC 控制面;control.stats 打开 stats 与 policy.system 流量计数。

典型用法

默认单节点场景下,最直接的用法是:按上面的示例填好 server.*,保持 inbound.protocol 为 http,takeover 用默认的 auto。这样插件会在探测通过后接管 DSH 进程的全局出口,无需手工设置代理环境变量。

启用 gRPC 控制面后,可以切换节点:启动顺序为写配置 → 起进程 → TCP 就绪 → 204 功能探测 → 接管 dispatcher → OverrideBalancerTarget(activeNode) 钉住出口。之后切换节点只改 balancer override,不动进程和入站。插件还提供三个可选的模型工具:xray_status(与 status.json 相同的状态快照)、xray_switch_node、xray_stats,均由 ctx.inject(['tools']) 可选注册;工具注册失败不影响代理本身工作,避免代理被工具可用性拖累。

关于入站协议,默认 HTTP;SOCKS 只作为可选附加,因为 DSH 代理策略明确拒绝 socks5:// URL,SOCKS 只能走内置 dispatcher,且失去 web_fetch 的覆盖。SOCKS 适合给非 Node 客户端使用。

功能探测默认请求 http://www.gstatic.com/generate_204,这是唯一能证明 uuid、flow、SNI、REALITY 全链路可用的检查,默认超时 5000ms。

适用场景与注意

适合需要在 DSH 内统一管理 xray 出口、做多节点切换、或希望在进程内看到明确状态和日志的开发者。如果已经通过系统代理或环境变量较好地解决了出口问题,没必要额外引入一层。

需要注意的几点:

  1. 插件以当前 DSH 进程权限运行,安装前应检查源码与许可证。许可证是 MIT,仓库提供 LICENSE 文件;Xray 二进制自身另有许可说明(见 bin/README.md)。
  2. 版本必须与 DSH 匹配:0.8.0 适配 DSH 0.2.2-rc.1,DSH 0.2.1 及以前使用 0.7.0。
  3. 端口策略是固定端口,冲突即失败,需自行确保 inbound.port 未被占用,且与 control.port 不冲突。
  4. takeover 可选 auto/force/off。已有代理策略时先试 auto,它会保留现有策略;只有在明确需要覆盖时才用 force。
  5. noProxy 不支持 CIDR,内网后缀按 routing.bypassDomains 配置。

插件目录页在 SkillHub(社区目录,与 DeepSeek / 幻方无官方从属关系),源码和文档在 GitHub:

  • https://www.skillhub.cn/plugins/TwinsEarth/DSH-2Xray
  • https://github.com/TwinsEarth/DSH-2Xray
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜