Xray 的 gRPC API 可以让运维脚本在不重启核心的情况下添加、移除或修改出站处理器,并查询出站流量计数。它适合节点池切换、按需启停备用线路和集中采集流量等场景,但不是完整的配置管理系统:API 动态修改不会自动写回启动配置,路由规则也不会因为新增出站而自动改变。要可靠上线,必须同时设计 API 监听范围、出站标签、流量统计策略、持久化和失败回滚。
本文面向维护 Xray 服务端或自建节点池的运维人员,说明如何启用 HandlerService 与 StatsService、通过 API 动态管理出站,以及按出站标签读取流量。文中还给出安全基线、操作步骤、统计配置与常见错误处理方法。示例中的地址和标签仅用于说明,接入前应按实际核心版本和运行环境核对。
一、API 能做什么,以及不能做什么
Xray gRPC API 是核心进程内部的控制接口。HandlerService 用于管理运行中的 inbound 和 outbound handler,常见操作包括添加、移除和修改出站;StatsService 则用于读取流量计数和系统统计。它们与客户端订阅更新不是一回事:v2rayN、v2rayNG 等客户端导入订阅,不会因此获得管理服务端 API 的权限。
动态出站适合让调度程序根据健康检查结果切换候选线路,或在维护期间临时加入备用出口。API 操作影响的是当前进程中的运行状态;如果没有同步更新磁盘上的 Xray 配置或外部配置数据库,核心重启后动态添加的出站不会自动恢复。因此,生产环境应把“期望配置”保存在可信的配置源中,API 作为应用变更的执行通道,而不是唯一的配置存储。
| 服务 | 主要职责 | 运维边界 |
|---|---|---|
HandlerService | 添加、移除或修改运行中的 handler,包括出站 | 新增出站不会自动建立路由规则,也不会写回启动配置 |
StatsService | 按名称或匹配模式查询流量统计,可按请求选择重置计数 | 只返回核心已启用并记录的统计项,不是历史账单系统 |
LoggerService | 在支持的接口中管理日志级别等运行时日志行为 | 不能替代日志轮转、访问控制和敏感信息清理 |
二、配置 API 入站与统计策略
Xray 配置通常通过专用的 API inbound 接收本机管理连接,并用路由规则把该 inbound 的请求送到 API 处理通道。以下是结构示意,监听端口使用常见的 10085 作为示例;如果端口已被占用,应选择未使用端口并同步修改管理客户端。
{
"api": {
"tag": "api",
"services": [
"HandlerService",
"StatsService"
]
},
"inbounds": [
{
"listen": "127.0.0.1",
"port": 10085,
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1"
},
"tag": "api-in"
}
],
"routing": {
"rules": [
{
"type": "field",
"inboundTag": ["api-in"],
"outboundTag": "api"
}
]
},
"stats": {},
"policy": {
"levels": {
"0": {
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
}
}
}
该片段展示 API 服务声明、API inbound、路由和出站计数策略之间的关系,不是完整可直接替换的服务器配置。正式合并时,要保留已有的 inbounds、outbounds、路由规则和策略;特别检查规则是否被更早的匹配项截走。若出站使用非默认用户等级或自定义策略,统计开关应配置在实际生效的等级上,而不能只照抄 0。
管理接口
- 服务
HandlerService、StatsService- 监听地址
127.0.0.1- 示例端口
10085- 路由标签
api-in→api
优先通过本机回环连接,不要直接绑定公网网卡。
出站流量计数
- 统计总开关
"stats": {}- 上传计数
statsOutboundUplink- 下载计数
statsOutboundDownlink- 查询维度
- 出站标签
按实际用户等级启用策略,并在 API 查询后验证计数是否增长。
配置变更后先运行与当前 Xray 版本相匹配的配置检查,再重启或按现有发布流程加载配置。确认核心启动日志没有 API、路由或策略解析错误,并从本机连接 127.0.0.1:10085 验证服务可达。核心的配置字段和 API protobuf 定义可能随版本演进,自动化程序应固定并测试核心版本,不能假设不同版本的消息结构完全相同。
三、HandlerService 如何动态管理出站
HandlerService 的关键输入是 Xray API protobuf 定义中的出站配置对象,而不是任意一段顶层 Xray JSON。操作流程通常是:使用与目标核心版本兼容的 protobuf 绑定构造请求,将完整的出站 handler 配置提交给 AddOutbound;移除时使用准确的出站标签调用 RemoveOutbound;修改已有出站则调用对应的变更方法,并按该版本定义构造操作消息。
出站配置包含协议类型及协议专属设置,还可能包含发送器、传输、安全层和代理设置。仅发送一个标签,或把节点分享链接直接当成 API 请求体,都不足以建立可用出站。比较稳妥的做法是以经过验证的静态 Xray 配置为来源,用与当前核心版本对应的配置解析器或 protobuf 代码生成对象,再调用 gRPC。若工具使用 JSON 编码 protobuf 请求,应按该消息的 protobuf JSON 规则编码,不能把普通配置文件中的 outbounds 数组原样塞入请求。
-
准备基线
在版本控制或受控配置库中保存已验证的 Xray 配置,记录核心版本、出站协议、标签、服务器地址、端口和传输参数。示例端口
443只代表常见值,不可替代服务端实际参数。 -
校验唯一标签
为每个出站分配稳定且唯一的标签,例如
pool-edge-a。调用前读取当前运行状态或维护标签登记表,避免重复添加;标签还必须与路由规则及监控查询使用的名称一致。 -
构造请求对象
用匹配核心版本的 API protobuf 绑定构造
OutboundHandlerConfig,并按对应协议填充类型化配置。不要手工拼接未经校验的 Any 字段,也不要把认证凭据写进命令行参数或普通日志。 -
添加并检查
通过本机 gRPC 客户端调用
HandlerService.AddOutbound,检查返回状态,再查询运行中的出站或执行受控连通性测试。添加成功只说明 handler 被接受,不代表业务路由已经切换到它。 -
切换后回滚
先更新调度逻辑或路由,使新连接使用目标出站;观察连接错误和流量后,再移除旧出站。若添加或路由更新失败,恢复上一份期望配置,避免删除仍被业务使用的出口。
移除前应确认路由不再把新连接发送到该标签,并考虑现有连接的处理方式。运行中移除 handler 对既有连接的影响可能与核心版本及连接状态有关,不能仅凭 API 返回成功就假定所有会话已平滑迁移。需要无损切换时,应先停止新流量进入旧出站,等待连接排空或设置可验证的维护窗口,再执行移除。
四、通过 StatsService 查询上传与下载
出站流量统计通常以出站标签形成统计名称,常见格式为 outbound>>>标签>>>traffic>>>uplink 和 outbound>>>标签>>>traffic>>>downlink。实际名称应以当前核心版本的 API 返回结果为准。通过 GetStats 查询单个统计项适合按已知标签定点读取;QueryStats 则可用匹配模式批量查询。查询请求中的 reset 选项会影响计数状态,日常轮询通常应关闭重置,避免两个采集器互相清零。
计数值通常是自核心启动或上次重置以来累计的字节数,不应直接当作某个自然日的账单。采集器可按固定间隔读取计数、保存带时间戳的快照,再以相邻两次读数的差值计算区间流量。若读数变小,应检查是否发生了核心重启、显式 reset、标签重建或统计项生命周期变化;不要把负差值当成真实流量。
- 标签要稳定:出站改名后,旧统计名称不会自动变成新标签。监控系统应记录标签变更,并明确新旧时间序列的边界。
- 两个方向要分开:上传和下载的含义以 Xray 统计项定义为准;对外展示时应明确单位是字节、KiB 还是 MiB,并使用一致的换算方式。
- 不要高频无节制轮询:按业务需要设置采集周期,例如先从 10 至 30 秒开始观察 API 调用量,再根据监控精度调整。
- 缺项不等于零流量:若统计策略未启用、标签不存在或计数项尚未创建,查询可能没有返回该项。应区分“未找到”和“计数为零”。
结论:统计增量比累计值更适合告警
先以不重置方式定期采集上传、下载计数,再计算时间窗口内的增量。这样能保留核心累计状态,也更容易识别采集遗漏、重启和异常突增。
五、权限隔离、超时与幂等处理
gRPC 管理接口拥有改变运行状态的能力,应按控制平面处理。最小化暴露面是首要措施:监听回环地址,通过本机运维代理或受控隧道访问;确需跨主机管理时,使用隔离网络、主机防火墙和经过验证的传输安全配置,并限制来源地址。不要把 API 端口加入面向所有用户的代理入站,也不要把未认证的明文 gRPC 监听在公网地址上。
自动化程序还要把超时和重试纳入设计。网络超时并不能证明服务端没有执行操作:客户端发出添加请求后连接中断,核心可能已经完成添加。直接重试可能得到重复标签错误。可采用“先检查状态,再决定是否重试”的幂等流程:调用前检查标签,超时后重新查询运行状态;确认不存在才重试,确认已存在则比较配置是否符合期望,而不是盲目再次新增。
报错:connection refused
原因与解法:API inbound 未启动、监听地址或端口不匹配,或本机防火墙拒绝连接。检查 Xray 启动日志、实际监听的 127.0.0.1:10085 与客户端目标地址;不要因此把监听地址改为公网地址。
报错:unknown service
原因与解法:配置中没有启用所调用的服务,或客户端使用的服务名与核心 API 定义不匹配。核对 api.services,并确认生成的 protobuf 客户端与目标核心版本兼容。
报错:already exists 或标签重复
原因与解法:相同标签的出站已存在,可能是上次请求成功但响应丢失。先读取当前 handler 状态,再比对目标配置;不要通过不断改名掩盖重复执行问题。
报错:查询结果中没有出站流量项
原因与解法:可能是统计策略未启用、策略等级不匹配、标签拼写错误,或该项尚未产生。检查 statsOutboundUplink 与 statsOutboundDownlink,让对应出站产生测试流量后再查询。
运维日志只记录操作类型、目标标签、调用耗时、结果码和请求关联编号,不记录完整节点配置、用户凭据或含密钥的序列化请求。把 API 凭据与普通应用配置分开存储,并限制读取权限;对添加、移除和修改操作保留审计记录,注明触发人、变更原因及回滚结果。
六、常见问题
调用 AddOutbound 成功,为什么流量没有走新节点?
添加 handler 只让出站在运行时可用,不会自动改写路由。检查相关路由规则的顺序、匹配条件和 outboundTag,确认新连接确实被分配到新标签,再查看该标签对应的统计项是否增长。
核心重启后,API 添加的出站还在吗?
通常不会自动保留。将期望配置写入受控配置源,并在启动或部署流程中重新加载;不要把运行时 API 状态当成持久化配置。
能否每次查询流量都把计数清零?
不建议多个采集任务这样做。日常查询使用不重置选项,保存带时间戳的累计快照并计算差值;只有明确需要分段计数、且确认没有其他消费者时,才评估重置行为。
可以直接把节点 JSON 传给 gRPC 吗?
不能假设普通 Xray 配置 JSON 与 API 请求消息结构相同。使用目标核心版本对应的 protobuf 定义或配置解析器,将协议专属配置构造成 API 所需的类型化对象,再调用 HandlerService。
落地时建议先在隔离测试实例验证服务启用、出站添加、路由切换、流量查询和移除回滚,再逐步接入生产调度。把 API 版本、配置来源、标签规范和超时重试策略一起纳入变更记录,才能让动态管理既可自动化,也可审计和恢复。