哪吒 Dashboard、Agent 与 gRPC 的协作架构
解释 Dashboard、Agent、反向代理、CDN 与数据库如何共同完成状态采集和远程任务。
#type / synthesis
#status / evergreen
#tech / ops
#tech / network
#resource / nezha
#protocol / grpc
#platform / server
哪吒 Dashboard、Agent 与 gRPC 的协作架构
[!info] related notes
- 所属地图:哪吒监控 MOC
- 身份模型:哪吒 Agent 的用户密钥、UUID 与服务器记录
- 操作闭环:用 Caddy 与 Cloudflare 部署哪吒面板
- 故障闭环:哪吒 Agent 无法上线排查
[!abstract] 核心结论 “网页能打开”只证明 Web 链路可用;Agent 上线还要求同一入口完整通过 TLS、HTTP/2、gRPC 路径、鉴权头和长连接。
数据流不是一条普通网页请求
sequenceDiagram
participant A as Agent
participant E as DNS/CDN/反向代理
participant D as Dashboard
participant DB as SQLite
A->>E: TLS + HTTP/2 gRPC 建连
E->>D: 转发 /proto.NezhaService/*
D->>D: 校验用户密钥与 Agent UUID
D->>DB: 查找或创建服务器记录
A->>D: 周期上报系统信息
D->>DB: 保存配置与关系数据
D-->>A: 任务、配置或控制消息
初次连接时,Dashboard 根据用户连接密钥确定归属,再根据 UUID 识别数据源。之后 Agent 周期性上报状态。远程命令、终端和配置下发则沿已建立的控制通道返回 Agent。
四个必须同时成立的不变量
server指向的主机和端口在网络层可达。tls: true时,域名、证书和 SNI 必须匹配,除非明确接受不安全验证。- 反向代理必须把
/proto.NezhaService/*作为 gRPC 转发到 Dashboard 的 h2c 后端。 client_secret与用户身份匹配,uuid在每个逻辑 Agent 上保持稳定且唯一。
只满足前三项会得到鉴权错误;只满足 Web 页面访问会在 gRPC 探测时得到 HTML、403、404 或 502。
V1 之后为什么 Web 与 gRPC 共用端口
V1 起 Dashboard 的 Web 与 gRPC 默认共用 8008。这减少了需要暴露和维护的端口,但把协议分流责任交给反向代理:普通 HTTP/WebSocket 与 gRPC 使用同一域名时,代理必须根据路径和协议选择正确的上游传输。
CDN 有两种可行策略
| 策略 | Web 访问 | Agent 通信 | 主要代价 |
|---|---|---|---|
| 双域名 | CDN 域名 | DNS-only 通信域名 | 多维护一个域名,行为最清晰 |
| 单域名 | CDN 域名 | 同一 CDN 域名且启用 gRPC | 依赖 CDN 的 gRPC、HTTP/2 和安全规则 |
| 客户端 hosts 直连 | CDN 域名 | 保留 SNI 但解析到源站 | 源站必须放行 Agent IP,源站 IP 变更需同步 |
Cloudflare 未启用 gRPC 时会直接对 gRPC 请求返回 403 Forbidden。这不会影响普通网页,因此容易造成“面板正常但 Agent 全离线”的错觉。
最小协议验证
curl --http2 -v \
-H 'Content-Type: application/grpc' \
-X POST \
https://data.example.com/proto.NezhaService/
健康的协议入口通常返回 HTTP/2、content-type: application/grpc,并以 grpc-status: 12 表示调用了未知方法。这个结果不是业务成功,但证明请求已经穿过 TLS、CDN/代理并到达 gRPC 服务。