# Xboard 对接 V2bX 完整文档 本文基于以下两套源码交叉整理: - 面板端:`Xboard-new` - 节点端:`E:/code/go/V2bX` 适用目标:让 `V2bX` 节点稳定对接 `Xboard`,完成配置拉取、用户同步、流量上报、在线设备上报。 ## 1. 对接结论(先看这个) 1. `V2bX` 当前固定请求 `Xboard` 的 `V1 UniProxy` 路径(不是 `V2` 路径): - `GET /api/v1/server/UniProxy/config` - `GET /api/v1/server/UniProxy/user` - `GET /api/v1/server/UniProxy/alivelist` - `POST /api/v1/server/UniProxy/push` - `POST /api/v1/server/UniProxy/alive` 2. 鉴权依赖 URL Query 参数:`token`、`node_id`、`node_type`。 3. `Xboard` 的 `server_token` 长度需要 >= 16。 4. `V2bX` 启动时如果拉不到可用用户会直接报错退出:`add users error: not have any user`。 5. 在线设备数据写入由队列任务处理,面板端必须保证队列消费者(通常 `horizon`)在运行。 ## 2. 源码级接口对齐 ## 2.1 V2bX 侧(请求方) 关键实现: - `api/panel/panel.go`:初始化 Query 参数(`node_type/node_id/token`),并限制 `NodeType` 枚举。 - `api/panel/node.go`:拉取节点配置(`/api/v1/server/UniProxy/config`)。 - `api/panel/user.go`:拉取用户、在线列表,上报流量和在线 IP。 - `node/controller.go`:启动时先拉配置和用户,再注册节点。 - `node/task.go`:按 `pull_interval/push_interval` 定时同步与上报。 ## 2.2 Xboard 侧(服务方) 关键实现: - `app/Http/Routes/V1/ServerRoute.php`:`/api/v1/server/UniProxy/*` 路由定义。 - `app/Http/Middleware/Server.php`:校验 `token/node_id/node_type`,并注入 `node_info`。 - `app/Http/Controllers/V1/Server/UniProxyController.php`:实现 `config/user/push/alive/alivelist/status`。 - `app/Services/ServerService.php`:按 `node_id`(支持 `code` 或 `id`)和 `node_type` 查节点,按权限组取可用用户。 - `app/Jobs/UpdateAliveDataJob.php`:异步写在线设备计数。 ## 3. 类型与协议兼容要点 `V2bX` 允许的 `NodeType`(`api/panel/panel.go`): - `vmess` - `vless` - `trojan` - `shadowsocks` - `hysteria` - `hysteria2` - `tuic` - `anytls` - 兼容别名:`v2ray -> vmess` `Xboard` 节点类型(`app/Models/Server.php`)有别名: - `v2ray -> vmess` - `hysteria2 -> hysteria` 建议: 1. 绝大多数场景按面板节点真实类型填写 `NodeType`。 2. Hysteria v2 场景建议仍使用 `NodeType: "hysteria"`,在面板协议设置里把 `version` 设为 `2`,避免类型语义混乱。 3. `V2bX` 并不对接 `Xboard` 的 `socks/naive/http/mieru` 这几类。 ## 4. Xboard 面板端配置步骤 ## 4.1 全局通信参数 后台系统配置里设置: - `server_token`:与 V2bX 的 `ApiKey` 完全一致,长度建议 32+。 - `server_pull_interval`:节点拉配置周期(秒)。 - `server_push_interval`:节点推送流量周期(秒)。 - `device_limit_mode`:设备限制统计策略(按你的业务选)。 源码依据: - `app/Http/Controllers/V2/Admin/ConfigController.php` - `app/Http/Requests/Admin/ConfigSave.php` ## 4.2 创建节点(每个 NodeID 对应一个节点) 至少需要正确配置: - `type` - `name` - `host` - `port` - `server_port` - `group_ids` - `rate` - `protocol_settings`(按协议必填项) 源码依据:`app/Http/Requests/Admin/ServerSave.php` ## 4.3 用户可用性条件(非常关键) 节点可拉到的用户必须同时满足(`ServerService::getAvailableUsers`): - 用户 `group_id` 在节点 `group_ids` 内 - `u + d < transfer_enable` - 未过期 - 未被禁用 否则 `V2bX` 首次启动可能直接失败(无可用用户)。 ## 4.4 队列进程 `/alive` 上报会派发 `UpdateAliveDataJob` 到 `online_sync` 队列。 若没有队列消费者,在线设备统计会滞后或不更新。 建议至少保证: - `php artisan horizon` 正常运行 ## 5. V2bX 配置(可直接改) 参考 `E:/code/go/V2bX/example/config.json`。 ## 5.1 单节点最小可用示例 ```json { "Log": { "Level": "info", "Output": "" }, "Cores": [ { "Type": "sing", "Log": { "Level": "info", "Timestamp": true }, "OriginalPath": "/etc/V2bX/sing_origin.json" } ], "Nodes": [ { "Core": "sing", "ApiHost": "https://panel.example.com", "ApiKey": "请填写与Xboard一致的server_token", "NodeID": 1, "NodeType": "vmess", "Timeout": 30, "ListenIP": "0.0.0.0", "SendIP": "0.0.0.0", "DeviceOnlineMinTraffic": 200, "MinReportTraffic": 0 } ] } ``` ## 5.2 字段说明(高频踩坑项) - `ApiHost`:必须是面板根地址,不要写成 `.../api/v1`。 - `ApiKey`:对应 `Xboard server_token`。 - `NodeID`:对应面板节点 `id`(或数值型 `code`)。 - `NodeType`:必须是 V2bX 支持的枚举。 - `Timeout`:HTTP 超时秒数。 - `ApiSendIP`(可选):多网卡时指定请求源 IP。 源码依据:`E:/code/go/V2bX/conf/node.go` ## 6. 启动与热重载 ## 6.1 启动命令 ```bash V2bX server -c /etc/V2bX/config.json ``` 默认支持 `--watch`(开启配置监听),配置文件变化后会自动重载核心和节点。 源码依据:`E:/code/go/V2bX/cmd/server.go` ## 6.2 建议运行形态 - 使用 `systemd` 托管 `V2bX` - 配置 `Restart=always` - 单独落日志文件,便于排错 ## 7. 联调验证(建议按顺序) ## 7.1 手工验证面板接口可达 在节点机执行(把参数换成你的真实值): ```bash curl -sS "https://panel.example.com/api/v1/server/UniProxy/config?node_type=vmess&node_id=1&token=YOUR_TOKEN" ``` 预期:返回 JSON,包含 `base_config.push_interval` 与 `base_config.pull_interval`。 ```bash curl -sS "https://panel.example.com/api/v1/server/UniProxy/user?node_type=vmess&node_id=1&token=YOUR_TOKEN" ``` 预期:返回 `users` 列表,且非空(至少有一个可用用户)。 ## 7.2 启动后看 V2bX 日志 应出现这类信息: - `Core ... started` - `Nodes started` - 周期性 `Report N users traffic` - 周期性在线用户上报日志 ## 7.3 面板侧确认 - 节点状态 `last_check_at`、`last_push_at` 持续刷新 - 用户流量持续累加 - `online_count` 有变化(需要队列正常) ## 8. 常见问题与处理 ## 8.1 `unsupported Node type` 原因:`NodeType` 不在 V2bX 白名单。 处理:改为支持值(如 `vmess/vless/trojan/shadowsocks/hysteria/tuic/anytls`)。 ## 8.2 `Invalid token` 原因:`ApiKey != server_token`。 处理:面板与节点统一同一密钥,并确认没有前后空格。 ## 8.3 `Server does not exist` 原因: - `NodeID` 错误 - `NodeType` 与面板节点类型不匹配 处理:先在面板确认节点 ID/类型,再校正 V2bX 配置。 ## 8.4 `add users error: not have any user` 原因:该节点按权限组筛选后没有可用用户。 处理: 1. 确认节点 `group_ids` 2. 确认至少一个用户满足流量/到期/禁用条件 ## 8.5 在线设备不上报或不更新 原因:面板队列消费者未运行。 处理:启动并确认 `horizon` 正常消费(尤其 `online_sync` 队列)。 ## 8.6 配置路径重复导致 404 原因:`ApiHost` 写成 `https://panel/api/v1`,最终拼接成重复路径。 处理:`ApiHost` 只保留根域名(如 `https://panel.example.com`)。 ## 9. 请求/响应数据形状(排错用) ## 9.1 配置拉取 - 请求:`GET /api/v1/server/UniProxy/config?node_type=...&node_id=...&token=...` - 响应:按协议字段 + `base_config` ## 9.2 用户拉取 - 请求:`GET /api/v1/server/UniProxy/user?...` - 响应:`{"users":[{"id":1,"uuid":"...","speed_limit":0,"device_limit":0}]}`(也兼容 msgpack) ## 9.3 流量上报 - 请求:`POST /api/v1/server/UniProxy/push?...` - Body(V2bX 实际发送): ```json { "1001": [12345, 67890], "1002": [11111, 22222] } ``` ## 9.4 在线上报 - 请求:`POST /api/v1/server/UniProxy/alive?...` - Body: ```json { "1001": ["1.1.1.1", "2.2.2.2"], "1002": ["3.3.3.3"] } ``` ## 10. 安全建议 1. `ApiHost` 必须用 HTTPS。 2. `server_token` 使用高强度随机值并定期轮换。 3. 在反向代理/Nginx 层限制节点来源 IP 访问 `server/UniProxy` 接口。 4. 变更 `server_token` 后,面板与全部节点必须同时切换。 ## 11. 代码参考索引 Xboard: - `app/Http/Routes/V1/ServerRoute.php` - `app/Http/Middleware/Server.php` - `app/Http/Controllers/V1/Server/UniProxyController.php` - `app/Services/ServerService.php` - `app/Jobs/UpdateAliveDataJob.php` - `app/Http/Requests/Admin/ConfigSave.php` - `app/Http/Requests/Admin/ServerSave.php` V2bX: - `api/panel/panel.go` - `api/panel/node.go` - `api/panel/user.go` - `node/controller.go` - `node/task.go` - `node/user.go` - `conf/node.go` - `cmd/server.go` - `example/config.json`