路由出站
在线演示:节点管理 + 路由出站
Section titled “在线演示:节点管理 + 路由出站”下面是节点管理表的本地 mock 复刻 — 启停 / 复制订阅 / 路由出站 / 编辑 / 删除全可点;点节点行的「路由出站」按钮(右侧表格里那个紫色路径图标)即可打开「新增落地节点」对话框,跟主控里完全一致。
| 节点名称 | 服务器 | 协议 | 流量 | 状态 | 操作 |
|---|---|---|---|---|---|
🇭🇰 HK直连 | hk1.example.com | VLESS | ↑ 12.30 GB ↓ 184.70 GB | ||
🇺🇸 US-Reality | us1.example.com | VLESS | ↑ 3.10 GB ↓ 46.50 GB | ||
🇯🇵 JP-Hy2 🇯🇵 JP → HK直连 | jp1.example.com | Hysteria2 | ↑ 8.70 GB ↓ 112.30 GB | ||
🇸🇬 SG-Trojan | sg1.example.com | Trojan | ↑ 0 B ↓ 0 B | ||
🇩🇪 DE-Reality | de1.example.com | VLESS | ↑ 1.40 GB ↓ 17.80 GB | 已禁用 |
出站的两种配置方式
Section titled “出站的两种配置方式”在节点管理页面,每个节点行的「创建链式出站」按钮(双向箭头图标)可以打开「新增落地节点」对话框。对话框顶部「作用范围」提供两种完全不同的能力:

新增落地节点:作用范围(整个节点 / 子节点)、选择落地节点 / 选择服务器 / 选择负载均衡器三个选项卡
顶部工具栏的「路由出站」按钮则打开路由出站总览,列出已创建的全部 routed 子节点:

路由出站管理:说明区 + 已创建的路由出站列表(尚未创建时为空)
使用前提(普通用户):路由出站对普通用户是一个需要管理员开启的功能。管理员在「系统设置 → 妙妙屋功能设置」找到「允许用户创建路由出站」开关。开关右侧可配置 数量上限(默认 2)和 每日操作次数(默认 5),未开启时两个输入框都被禁用。
未开启时,普通用户的节点行不会出现 「路由出站」按钮;如果通过其他途径调用接口:
- 功能未启用 → 后端返回 403「路由出站功能未开放,请联系管理员开启」
- 数量达上限 → 403「已达到路由出站数量上限 (N/M)」
- 今日操作次数达上限 → 429「今日操作次数已达上限 (N/M),请明天再试」
对话框「作用范围」两种模式:
| 作用范围 | 影响 | 是否新增节点 |
|---|---|---|
| 整个节点 | 源 inbound 的全部用户共享同一出站 | 否,仅改源节点出站 |
| 按用户(路由出站) | 仅套餐里勾选该子节点的用户走此出口 | 是,生成一个路由出站子节点 |
本文档重点讲解「按用户」模式,即 路由出站。
整个节点(节点级)
Section titled “整个节点(节点级)”源节点的入站流量整体路由到一个出口,该 inbound 下所有用户共享同一出站。
底层动作(写入源服务器 xray 配置):
- 加 outbound,tag = landing-
<源 inbound tag>-<时间戳> - 加 routing 规则:
{inboundTag: [源 inbound], outboundTag: 上一步 tag}
适用场景:所有用户都该走同一出口,例如“前端入口机 → 后端落地机”统一中转、统一出口接管。
路由出站解决了什么问题?
Section titled “路由出站解决了什么问题?”在没有「用户」维度的 routing 系统里,一个 inboundTag → outboundTag 的关系只能有一个版本,无法实现“不同用户走不同出口”。
下面用一个具体例子说明。本文档统一使用以下三个节点:
| 类型 | 节点名 | 地址 / 备注 |
|---|---|---|
| 落地 | HKT | hkt.example.com |
| 落地 | HINET | hinet.example.com |
| 中转 | HK直连 | hkdirect.example.com(vless reality vision,443) |
假设管理员希望「访问 AI 服务的流量走 HINET 出口」,写一条 routing 规则:
{ "type": "field", "domain": ["geosite:openai"], "inboundTag": ["HK直连"], "outboundTag": "HINET"}但用户 A 有自己的 Seednet 落地机,希望「自己的 AI 流量走 Seednet」。传统做法只能再加一条同 inbound 不同 outbound 的规则——xray routing 按顺序匹配,第一条命中即停止,后加的永远不生效。
根本问题:没有任何手段区分这两条规则要应用到“谁的流量”。
路由出站的做法
Section titled “路由出站的做法”妙妙屋X 为每个用户在父 inbound 里注册一个专属 client(独立 email),对应的 routing 规则带上 user 字段限定。不同用户的 email 不同,所以可以并存多条「同 inbound、不同 outbound」的规则。
⚠ 当前路由出站只能由管理员创建(接口 POST /api/admin/routed-outbound)。文档中“用户 A 走 Seednet”是指管理员为用户 A 创建一个路由出站子节点,并把 A 在套餐里分配到该节点,而不是用户自助配置 routing。
- 在节点管理页面,找到中转节点 HK直连,点击行尾的 「路由出站」按钮
- 「作用范围」选择 按用户(路由出站)
- 填写 Label(仅允许 [a-zA-Z0-9-],长度 2-32),例如 rout-hinet
- 选择目标落地节点(如 HINET),点击「创建路由出站」
- 系统在节点列表新增子节点 HK直连-rout-hinet,node_type = routed
- 在套餐管理中勾选这个子节点,分配给指定用户即可生效
生成的 routing 规则示例
Section titled “生成的 routing 规则示例”管理员创建 HK直连-rout-hinet(落地 HINET)和 HK直连-rout-seednet(落地 Seednet)两个路由出站子节点后:
// 管理员占位规则(尚无用户分配时也存在,user 是占位 admin email){ "type": "field", "user": ["_admin__a1b2c3__hinet"], "domain": ["geosite:openai"], "inboundTag": ["HK直连"], "outboundTag": "HINET"}
// 用户 A 被套餐分配到 HK直连-rout-seednet 后,// A 的子账号 email 会被自动加进这条规则的 user 列表{ "type": "field", "user": ["userA__d4e5f6__seednet"], "domain": ["geosite:openai"], "inboundTag": ["HK直连"], "outboundTag": "Seednet"}email 实际格式:<username>__<short>__<label>,管理员占位为 _admin__<short>__<label>。short 是创建路由出站时随机生成的标识,用于在同 label 多次创建时区分。
目标不止是落地节点
Section titled “目标不止是落地节点”在「新增落地节点 → 子节点(路由出站)」里,除了选落地节点,管理员还有三种选法:
- 一次选多个落地节点:连点多个节点,按点选顺序逐个创建,Label 自动生成。
- 用这台服务器上已有的出站:列出服务器 Xray 配置里现有的出站(不含内置的直连 / 拦截),包括手动写进去的。显示成落地节点名字的,点一下等于再选一次那个落地节点;其余的按它的配置复制一份。
- 用这台服务器上已有的负载均衡器:列出「Xray 配置 → 路由管理 → 负载均衡」里已有的均衡器,点一下建一个子节点,流量交给这个均衡器在成员出站之间分配。这种子节点不新建出站,之后改均衡器的成员或策略会直接生效;节点列表里显示成
⚖ 均衡器名。还有子节点指向它时,均衡器不能删除。
普通用户视角(按用户私有路由出站)
Section titled “普通用户视角(按用户私有路由出站)”管理员在「系统设置」开启「允许用户创建路由出站」后,普通用户可以为自己创建专属出口,不依赖套餐分配,创建即生效。与管理员路径的差异:跳过 admin 占位,rule.user 创建时直接是用户本人的子账号 email;节点 routed_owner = ‘user’,仅创建者可见可删。
位置:管理员账号登录 → 「系统设置」 → 「妙妙屋功能设置」卡片 → 「允许用户创建路由出站」一行。
- 关闭(默认):普通用户节点行不显示 「路由出站」按钮;接口 POST 返回 403。
- 开启:右侧 Switch 打开后,「数量」「每日次数」两个输入框启用。
- 数量:当前持有的路由出站上限。默认 2;可调到任意 ≥1 的整数。不支持“不限”(每条路由出站都会在 xray 上新增 outbound + routing rule,无限制可能导致配置膨胀)。
- 每日次数:今日内 create + delete 操作次数总和上限。默认 5;可调到任意 ≥1 的整数。不支持“不限”。设计原因:xray routing 不支持 gRPC 动态加载,每次新增 / 删除路由出站后 agent 都会自动重启 xray。频繁触发重启会影响其他用户连接,所以“按操作次数限速”。
- 计数窗口:按主控服务器本地时区当日 0:00 起算,到 24:00 重置;不滚动。
- 修改即生效:Switch 切换 / 输入框失焦时立即保存到 system_settings 表。
- 普通用户在节点管理页面,找到自己可见的中转节点(套餐分配的节点或自己导入的),点击行尾 「路由出站」按钮
- 对话框只显示「路由出站(按用户)」模式(管理员的「整个节点」radio + 服务器 Tab 都不显示)
- 从「从已有节点选」Tab 选一个落地节点
- Label 自动填 rout-
<目标 slug>,可手动改 - 点「创建路由出站」
系统在节点列表新增一行 <中转节点>-<label>,该行只对创建者本人可见,并自动进入用户订阅。
删除自己的路由出站
Section titled “删除自己的路由出站”创建的路由出站节点行右侧会显示一个 🗑 删除按钮(仅创建者可见)。点击后会清理 xray 上对应的 outbound、routing rule、用户 client,以及 DB 中的节点行 + user_subaccounts 记录。删除不受 enabled 开关限制——即使管理员关闭了开关,用户仍能清理已存在的路由出站。
暂停 / 恢复
Section titled “暂停 / 恢复”以下三种情况触发用户私有路由出站自动暂停(拆 rule + client,保留 outbound + 凭据):
- 管理员在用户管理停用该用户(is_active=false)
- 套餐到期(package_end_date < now)
- 流量超限(traffic limit enforcer 拉黑)
对应恢复触发点(重建 rule + 加回 client):
- 启用用户
- 流量恢复到限额以下
注意:套餐到期时由于失去对父 inbound 的访问权,路由出站会被自动暂停,但不会自动恢复(要求重新绑定套餐)。
进阶:一中转多落地的流量拼车
Section titled “进阶:一中转多落地的流量拼车”同一个中转 inbound 上挂多个出站,复用中转的端口、UUID、Reality 配置,套餐里直接发给用户。适合用一台中转机做多区域分流的场景。
一台 HK直连 中转机 + 两个落地(HKT、HINET),通过路由出站创建出两个 routed 子节点:
| 子节点名 | 父 inbound | 出站 | outbound tag |
|---|---|---|---|
| HK直连-rout-hkt | HK直连 | HKT | routed:p<父 id>:rout-hkt |
| HK直连-rout-hinet | HK直连 | HINET | routed:p<父 id>:rout-hinet |
套餐里同时勾选这两个子节点发给用户,用户订阅里就看到两条线路,底层共用同一个中转 inbound:
- ✓ 节省中转机端口与 Reality 配置(不用为每个落地各开一个入站)
- ✓ 中转 inbound 维度的流量自然聚合(便于查看中转机总进出口压力)
- ✓ 用户级流量仍按子账号 email 独立计费
- ✓ 用户对中转换落地无感切换,体验上等同两条独立线路
底层实现要点
Section titled “底层实现要点”创建路由出站时
Section titled “创建路由出站时”- 在父物理节点的 inbound 里加一个占位 admin client(email = _admin__
<short>__<label>) - 在源服务器上加一个 outbound,tag = routed:p
<父节点 id>:<label> - 在 routing 规则数组顶部 prepend 一条带 marktag 的规则,user = [admin_email]
- 在主控数据库 nodes 表写入子节点行(node_type=routed,parent_node_id,routed_outbound_tag)
套餐分配用户到该子节点时
Section titled “套餐分配用户到该子节点时”- 为用户在父 inbound 中加一个子账号 client(email =
<username>__<short>__<label>,UUID 独立生成) - 把该 email 追加到 routing 规则的 user[] 数组
- 凭据写入 user_subaccounts 表,续费 / 恢复时复用同一组凭据
路由出站子节点的 clash_config 来自父 inbound,订阅生成时把节点中的 UUID 替换为该用户的子账号 UUID,节点名替换为子节点配置的 NodeName。这样客户端连入时使用子账号 email,xray 命中带 user 限定的 routing 规则,被转到指定 outbound。
流量统计与 email 反查
Section titled “流量统计与 email 反查”xray stats 上报的 user.<email> 指标,会通过 user_subaccounts.email → username 反查到 mmwx 用户名,最终归集到该用户的总流量。
因此即使一个用户有多个子账号(订阅了多条路由出站子节点),流量也能正确合并到其主账号。
对比:节点级 vs 用户级
Section titled “对比:节点级 vs 用户级”| 维度 | 整个节点(节点级) | 按用户(路由出站) |
|---|---|---|
| 影响范围 | 源 inbound 全员 | 仅套餐勾选的用户 |
| 是否新增订阅节点 | 否 | 是(一个 routed 子节点) |
| 多用户差异化出口 | ✗ | ✓ |
| 一中转挂多落地 | ✗ | ✓ |
| 是否触发 xray 重启 | 是 | 是(首次创建及每次新增用户) |
| 流量统计粒度 | inbound 整体 | 按用户 email 独立 |
路由出站节点的解锁结果(节点管理里的锁图标、客户端里的解锁标识)取的是它真实出口的检测结果:
- 落地是本面板管理的服务器:直接引用那台服务器的检测结果。
- 落地是外部线路(别家的家宽、外部订阅里的节点)或 WARP:由宿主服务器的 Agent 经这条路由出站单独检测,结果按节点保存。需要 Agent v0.9.1 及以上;新建这类节点后 10 分钟内会自动补测一次,之后随每日 04:40 的例行检测更新。
- 落地被阻断(blackhole)或出站配置对不上:不显示,避免拿宿主服务器的结果冒充。
经出站测出的结果可能和宿主服务器自身的结果不同,这是正常的:它反映的是流量经这条出站实际出去的路径,例如落地机的 Xray 优先走 IPv6 时,部分服务按 IPv6 地址判定地区。
路由出站子节点能否删除?
Section titled “路由出站子节点能否删除?”可以。在节点管理页或顶部「路由出站」面板里删除。删除时系统会清理父 inbound 上的占位 client、所有用户子账号 client、以及 routing 规则。
同一个父节点能创建几条路由出站?
Section titled “同一个父节点能创建几条路由出站?”无硬性限制。每条用不同的 Label 区分。常见用法是为每个落地各创建一条。
用户同时分配到多个路由出站子节点会怎样?
Section titled “用户同时分配到多个路由出站子节点会怎样?”用户在父 inbound 上会有多个子账号 client(每条路由出站各一个),订阅里看到多条线路。xray routing 按规则顺序匹配,每个子账号 email 命中各自的规则,互不影响。
普通用户能不能自己加 routing 规则?
Section titled “普通用户能不能自己加 routing 规则?”直接加 routing 规则不行(那是 admin 接口)。但管理员可以在「系统设置 → 妙妙屋功能设置」打开「允许用户创建路由出站」开关,之后普通用户即可在自己可见的节点上自助创建私有路由出站(受配额限制,默认 2)。这条接口路径是 POST /api/user/routed-outbound。
开关关掉后,已有的用户路由出站会怎样?
Section titled “开关关掉后,已有的用户路由出站会怎样?”保留,已配置好的 outbound 和 rule 不会自动拆除,订阅里的节点仍能正常使用。关掉的只是“创建新的”能力。用户仍然可以删除已有节点(删除接口不受 enabled 开关限制)。如需“全清”,管理员可以在用户管理删除该用户,会级联清理其全部私有路由出站。
数量限制为什么没有“不限”选项?
Section titled “数量限制为什么没有“不限”选项?”用户私有路由出站每条都会在 xray 配置里新增一个 outbound + 一条 routing rule。如果允许“不限”,恶意用户或脚本能在短时间内塞满 xray 配置导致重启缓慢甚至 OOM。默认 2、上限由 admin 显式配置,是一种压舱设计。
为什么要限制“每日操作次数”?
Section titled “为什么要限制“每日操作次数”?”xray 的 routing 模块不支持 gRPC 动态加载规则——任何 rule 变更(新增、删除、改 user[])都必须重启 xray 进程才能生效。所以每次普通用户 create/delete 路由出站,agent 都会自动重启同节点上的 xray,会瞬间打断同机器上其他用户的连接(重连即可恢复,但体验受影响)。“数量上限”防的是累积持有,“每日操作次数”防的是短时频繁变动,两者是互补的。默认 5 次/天足够普通用户日常切换出口节点;超额返回 429 Too Many Requests。
每日次数是怎么计数的?
Section titled “每日次数是怎么计数的?”主控数据库新建了一张表 user_routed_outbound_actions(username, action, created_at),每次 POST/DELETE 成功(不含被校验拒绝的请求)都会写一条 create 或 delete 日志。校验时按主控服务器本地时区当日 0:00 起的行数计算;不是滚动 24 小时窗口。跨日后自动归零。
admin 创建路径会受这两个限制吗?
Section titled “admin 创建路径会受这两个限制吗?”不会。/api/admin/routed-outbound 是给管理员管理“套餐路由出站池”用的,不受用户配额 / 每日次数限制约束。两条接口的内部行为也不同:admin 路径有占位 admin client,用户路径没有(详见上文「整个节点 vs 按用户」对比)。