Files
new-api-key-usage/docs/delivery/部署文档.md
T
skycurtain 0e9db439ba docs: 收尾(阶段 8)——部署文档 + 端到端走查 + 文档状态
- docs/delivery/部署文档.md:前置条件 / 环境变量 / 一条命令链 / systemd 与 Nginx 示例 / 首次运行检查 / 运行约束(后端单实例 · 3 天窗口 · 主密钥 · 401 摘除)/ 升级 / 排查
- 从零端到端走查:清库 → db:push → 启动(空转 + QPU 基线)→ 管理面登记 → 引擎立即补一轮(984 条)→ 查看面查询(未折算「—」)→ 补录购买记录 → 金额出现 → 换算参数时间线;无 pageerror
- 8 篇设计文档状态 → 已实现(2026-09-15)
- README:状态行 / 文档地图(含 delivery)/ 下一步(部署 + 待补验与裁决清单)
- AGENTS.md:项目速览更新
2026-09-15 01:10:55 +08:00

153 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 部署文档
> 交付给实例运营方的安装与运行说明——**一条命令链**可跑(见 §3)。前后端**独立部署**:后端单进程常驻;前端为静态产物,由反代托管。
| 项目 | 内容 |
|------|------|
| 状态 | 定稿(2026-09-15) |
| 适用 | new-api-key-usage(针对 NewAPI 的 key 用量统计工具) |
| 关联 | `README.md`(项目全景与设计依据)· 仓库根 `.env.example`(环境变量样例) |
| 不含 | 反向代理软件本身的安装(假定服务器已有 Nginx 或等价物) |
---
## 0. 前置条件
| # | 项 | 要求 |
|---|----|------|
| 1 | 服务器 | Linux x86_64;可**出网访问 NewAPI 站点**(工具需轮询其接口) |
| 2 | 运行时 | **Bun ≥ 1.4**(安装:`curl -fsSL https://bun.sh/install \| bash`) |
| 3 | 数据库 | **PostgreSQL ≥ 14**(可用服务器现有实例;建议新建独立库与独立账号) |
| 4 | 反向代理 | Nginx 或等价物——**必须能配置 `/api` 反代规则**(前后端连线以同域反代为主,见 README 工程注记) |
## 1. 交付物
- 源码(git 仓库或压缩包),根目录为 Bun workspaces monorepo:
- `apps/server` —— 后端(Hono API + 同步引擎同进程)
- `apps/web` —— 前端(构建为静态产物 `apps/web/dist`)
- `packages/shared` —— 前后端共享的契约类型
- 无预编译产物要求:后端由 Bun 直接运行 TypeScript;前端产物在部署机执行一次构建即可。
## 2. 环境变量
在仓库根创建 `.env`(**不入库**):
| 变量 | 必填 | 说明 | 生成 / 填法 |
|------|------|------|------------|
| `PORT` | 否 | 后端监听端口(默认 3000) | 如 `3000` |
| `DATABASE_URL` | **是** | PostgreSQL 连接串 | `postgres://用户:密码@主机:5432/库名` |
| `MANAGE_TOKEN` | **是** | 管理面口令(`X-Manage-Token`) | `openssl rand -hex 16` |
| `KEYS_MASTER_KEY` | **是** | 凭证主密钥(**丢失 = 全部 key 需重新登记**) | `openssl rand -base64 32`(32 字节 base64) |
| `NEWAPI_BASE` | **是** | 上游 NewAPI 站点地址(不带尾斜杠) | 如 `https://your-instance.example.com` |
> `UPSTREAM_SOURCE` / `NEWAPI_FIXTURE_DIR` 仅开发期使用(见实施计划 §6),**生产不要设置**(默认走真实站点)。
## 3. 一条命令链
在仓库根依次执行:
```bash
bun install # 1) 安装全部依赖(含前端)
bun run db:push # 2) 建表(首次;四张表 + 索引)
# 生产首次也可用 db:generate + db:migrate(迁移文件入库)
bun run --filter '@naku/server' start # 3) 启动后端(前台;常驻见 §4)
# 启动即跑一轮同步,随后每 5 分钟一轮
bun run build # 4) 构建前端产物 → apps/web/dist
```
## 4. 常驻运行(systemd 示例)
`/etc/systemd/system/naku-server.service`:
```ini
[Unit]
Description=new-api-key-usage server
After=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/new-api-key-usage/apps/server
# .env 由应用从仓库根读取(apps/server 的上两级)
ExecStart=/root/.bun/bin/bun run /opt/new-api-key-usage/apps/server/src/index.ts
Restart=always
RestartSec=5
# 可选:环境变量也可直接注入(优先级高于 .env)
# Environment=PORT=3000
# Environment=DATABASE_URL=postgres://...
[Install]
WantedBy=multi-user.target
```
```bash
systemctl daemon-reload && systemctl enable --now naku-server
journalctl -u naku-server -f # 观察 [sync] 日志
```
## 5. 反向代理(Nginx 示例)
```nginx
server {
listen 80;
server_name usage.example.com;
# 前端静态产物(同源,前端用相对路径 /api)
root /opt/new-api-key-usage/apps/web/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html; # SPA 路由回退
}
# 后端 API(前后端连线:同域反代)
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
> 跨源直连(前端与后端不同域)亦可,但需后端 CORS 白名单与前端运行时 API base(契约 约定 24);同域反代是默认形态、无 CORS 问题。
## 6. 首次运行检查
1. 后端日志出现两行:`[sync] 引擎启动:立即跑一轮,随后每 5 分钟一次` 与 `[sync] 轮次完成:0 key,成功 0,失败 0,新增日志 0 条…`(无 key 时正常空转)
2. 打开站点 → 管理面 `/manage/api-keys`(界面上不暴露入口,直接输入 URL)→ 输入 `MANAGE_TOKEN` 进入
3. 点「+ 登记 key」粘贴一个 sk-key → 登记成功后该 key 出现在清单(「数据截止」先显示「同步中」,一轮后变为时间)
4. 回到查看面 `/usage-log`,粘贴刚登记的 key → 查询 → 卡片与明细出现数据
## 7. 必须知道的运行约束
| # | 约束 | 说明 |
|---|------|------|
| 1 | **后端必须单实例** | 同步引擎随进程启动(5 分钟一轮)。多实例会重复轮询、互相覆盖 `log_synced_at`,并可能触发上游限流。systemd 单实例 + 不做水平扩展即可 |
| 2 | **3 天窗口** | 上游 `/api/log/token` 固定只返回最近 1000 条(当前速率下 ≈ 3 天)。同步停摆超过约 3 天,旧日志**永久丢失**(上游不提供回填接口)。日志落后 > 24h 时每轮打印 warning |
| 3 | **`KEYS_MASTER_KEY` 不可丢** | 该密钥加密存储全部 sk-key。丢失后无法解密 → 需在管理面重新登记全部 key(历史日志数据仍在) |
| 4 | **401 自动摘除** | 连续 3 轮返回 401 的 key 会被自动停用(`disabled_source = auto_401`);在管理面「启用」即可恢复(启用时会向上游验证) |
| 5 | **上游同站点共享** | 工具对上游的请求是只读查询(每 key 每 5 分钟 2 个请求),量级极小;若上游有更严格的限流策略,可调低 key 数量或延长周期(`apps/server/src/sync/policy.ts` 的 `TICK_MS`) |
| 6 | 真实 key 联调 | **待作者补验**:本地开发以实测响应快照验证(实施计划 §6),首次对真实站点登记时请在管理面确认「上游验证通过 + 首轮同步完成」 |
## 8. 升级流程
```bash
git pull # 或替换源码目录
bun install # 依赖有变化时
bun run db:push # schema 有变化时(会提示确认)
bun run build # 重建前端产物
systemctl restart naku-server # 重启后端(引擎随启动立即补一轮)
```
## 9. 故障排查
| 现象 | 排查方向 |
|------|---------|
| 查看面「数据截止」显示「数据同步中…」 | 后端日志 `[sync]` 是否有该 key 的失败行;新登记 key 等一轮即可 |
| 查看面长时间数据不更新 | 是否「已失效(auto_401)」——管理面看状态徽章;或后端是否在运行 |
| 登记返回「上游暂不可用」 | 服务器到 `NEWAPI_BASE` 的网络连通性(`curl -sS $NEWAPI_BASE/api/status`) |
| 页面加载但查询 502 | 反代 `/api` 规则与后端端口是否一致 |
| 金额列显示「—」 | 该日志所属订阅尚未登记购买记录 → 管理面「购买记录」按观测提示补录 |
| 管理面全部 401 | `MANAGE_TOKEN` 与请求头是否一致(口令存 sessionStorage,关标签后需重新输入) |