docs: 添加项目说明与生产部署文档
This commit is contained in:
@@ -1,181 +1,343 @@
|
|||||||
# LLM 中转网关 · PM2 部署说明
|
# openai_node · 生产部署文档
|
||||||
|
|
||||||
本文说明如何在服务器上使用 **PM2** 守护 **FastAPI(uvicorn)** 进程,实现崩溃自动拉起、开机自启与日志管理。
|
本文说明如何在 **VPS** 上部署本网关,并通过 **宝塔面板** 反向代理、**frp** 汇聚多台本地 Ollama 节点。适用于当前推荐拓扑:
|
||||||
|
|
||||||
|
- 网关监听:**8150**
|
||||||
|
- 宝塔反代:域名 → `127.0.0.1:8150`
|
||||||
|
- 各 PC 模型端口:**3313–3318**(frp 映射到 VPS 本机 `127.0.0.1`)
|
||||||
|
|
||||||
|
代码仓库:[https://git.bz121.com/dekun/openai_node.git](https://git.bz121.com/dekun/openai_node.git)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. 前置条件
|
## 1. 部署拓扑
|
||||||
|
|
||||||
| 组件 | 说明 |
|
```
|
||||||
|------|------|
|
Internet
|
||||||
| **Python** | 建议 3.10+,已加入 `PATH` |
|
│
|
||||||
| **Node.js** | 用于安装 PM2(LTS 即可) |
|
▼
|
||||||
| **PM2** | `npm i -g pm2` |
|
┌─────────────────┐
|
||||||
| **本项目** | 含 `main.py`、`requirements.txt`,可选 `ecosystem.config.cjs` |
|
│ VPS │
|
||||||
|
│ 宝塔 Nginx:443 │
|
||||||
|
│ │ │
|
||||||
|
│ ▼ │
|
||||||
|
│ openai_node │
|
||||||
|
│ :8150 │
|
||||||
|
│ │ │
|
||||||
|
│ 127.0.0.1:3313 ├─── frp ─── PC1 Ollama :3313
|
||||||
|
│ 127.0.0.1:3314 ├─── frp ─── PC2 Ollama :3314
|
||||||
|
│ 127.0.0.1:3315 ├─── frp ─── PC3 Ollama :3315
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
上游本地大模型(默认 `http://127.0.0.1:10434`)需在同一台机器或内网可达;若在大模型同一主机部署网关,确保端口未被占用(下文示例为 **8000**)。
|
要点:
|
||||||
|
|
||||||
|
1. **不要**把 3313 等端口直接暴露到公网,仅 VPS 本机访问。
|
||||||
|
2. **不要**让宝塔直接把域名反代到各 PC;应只反代到 **8150**,由网关按 `model` 调度。
|
||||||
|
3. `nodes.json` 里 `host` 填 **`127.0.0.1`**,`port` 填 frp 映射后的端口。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. 准备运行环境
|
## 2. 前置条件
|
||||||
|
|
||||||
在 **项目根目录**(与 `main.py` 同级)执行:
|
| 组件 | 版本建议 | 用途 |
|
||||||
|
|------|----------|------|
|
||||||
|
| Python | 3.10+ | 运行网关 |
|
||||||
|
| Node.js | LTS | 安装 PM2 |
|
||||||
|
| PM2 | 最新 | 进程守护 |
|
||||||
|
| 宝塔 | 7.x+ | Nginx 反代、SSL |
|
||||||
|
| frp | 客户端 + 服务端 | 内网穿透(可用其它方案,原理相同) |
|
||||||
|
|
||||||
### Linux / macOS
|
各 PC 已安装 **Ollama** 并监听本地端口(如 3313),且与 VPS 网络可达(通过 frp)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 在 VPS 上部署网关
|
||||||
|
|
||||||
|
### 3.1 克隆代码
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /www/wwwroot # 按宝塔网站目录调整
|
||||||
|
git clone https://git.bz121.com/dekun/openai_node.git
|
||||||
|
cd openai_node
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 虚拟环境与依赖
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /path/to/中转网关
|
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
pip install -r requirements.txt -U
|
pip install -r requirements.txt -U
|
||||||
```
|
```
|
||||||
|
|
||||||
### Windows(PowerShell)
|
### 3.3 配置文件
|
||||||
|
|
||||||
```powershell
|
|
||||||
cd C:\path\to\中转网关
|
|
||||||
python -m venv venv
|
|
||||||
.\venv\Scripts\Activate.ps1
|
|
||||||
pip install -r requirements.txt -U
|
|
||||||
```
|
|
||||||
|
|
||||||
在项目目录创建 **`gateway.json`**(可复制 `gateway.json.example`),填写 **`username`**、**`password`**;**`api_key`** 可留空,首次启动会自动写入 `sk-...`。也可用环境变量 **`GATEWAY_CONFIG`** 指定配置文件绝对路径。
|
|
||||||
|
|
||||||
确认可手动启动:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m uvicorn main:app --host 0.0.0.0 --port 8000
|
cp gateway.json.example gateway.json
|
||||||
|
cp nodes.json.example nodes.json
|
||||||
|
chmod 600 gateway.json nodes.json
|
||||||
```
|
```
|
||||||
|
|
||||||
浏览器访问 `http://服务器IP:8000` 正常后再交给 PM2。
|
编辑 **`gateway.json`**:设置 `username`、`password`;`api_key` 可留空自动生成。
|
||||||
|
|
||||||
|
编辑 **`nodes.json`**(示例三台):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "node-1",
|
||||||
|
"name": "书房电脑",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 3313,
|
||||||
|
"enabled": true,
|
||||||
|
"max_concurrent": 1,
|
||||||
|
"models": [
|
||||||
|
{ "id": "qwen2.5:14b", "label": "千问 14B" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`models[].id` 必须与 Ollama 模型名、API 请求中的 `model` **完全一致**。
|
||||||
|
|
||||||
|
也可部署后浏览器打开 **系统设置** 页面维护(需先登录)。
|
||||||
|
|
||||||
|
### 3.4 环境变量
|
||||||
|
|
||||||
|
| 变量 | 生产建议 |
|
||||||
|
|------|----------|
|
||||||
|
| `JWT_SECRET` | **必改**,长随机字符串 |
|
||||||
|
| `GATEWAY_PORT` | `8150`(与 PM2、宝塔一致) |
|
||||||
|
|
||||||
|
可选:
|
||||||
|
|
||||||
|
| 变量 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `STATS_DB` | 统计库路径,默认 `gateway_stats.db` |
|
||||||
|
| `NODES_CONFIG` | 节点配置路径,默认 `nodes.json` |
|
||||||
|
| `UPSTREAM_URL` | 仅在没有配置 `nodes.json` 节点时作为单机上流 |
|
||||||
|
|
||||||
|
### 3.5 手动试跑
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export JWT_SECRET="你的随机密钥"
|
||||||
|
python -m uvicorn main:app --host 0.0.0.0 --port 8150
|
||||||
|
```
|
||||||
|
|
||||||
|
确认:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s http://127.0.0.1:8150/api/models/cards | head
|
||||||
|
curl -s http://127.0.0.1:3313/v1/models # frp 通了才有返回
|
||||||
|
```
|
||||||
|
|
||||||
|
浏览器访问 `http://VPS_IP:8150`,首页应出现模型卡片。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. 环境变量(生产必改)
|
## 4. PM2 守护
|
||||||
|
|
||||||
| 变量 | 含义 | 建议 |
|
项目已包含 **`ecosystem.config.cjs`**(端口 **8150**)。
|
||||||
|------|------|------|
|
|
||||||
| `JWT_SECRET` | 签发网页登录 JWT 的密钥 | 长随机字符串,勿泄露 |
|
|
||||||
| `UPSTREAM_URL` | 上游 OpenAI 兼容服务根地址(无末尾 `/`) | 默认 `http://127.0.0.1:10434`,按实际修改 |
|
|
||||||
|
|
||||||
可在 shell 中导出,或在 PM2 的 `env` / `ecosystem.config.cjs` 中配置(见下文)。
|
### 4.1 修改 PM2 配置
|
||||||
|
|
||||||
---
|
编辑 `ecosystem.config.cjs` 中 `env.JWT_SECRET` 为生产密钥。
|
||||||
|
|
||||||
## 4. 使用 PM2 启动(推荐 ecosystem)
|
### 4.2 启动
|
||||||
|
|
||||||
项目根目录已提供 **`ecosystem.config.cjs`**:自动根据 **Windows / 非 Windows** 选择虚拟环境中的 Python 解释器,并启动:
|
|
||||||
|
|
||||||
`python -m uvicorn main:app --host 0.0.0.0 --port 8000`
|
|
||||||
|
|
||||||
### 4.1 修改配置
|
|
||||||
|
|
||||||
1. 用编辑器打开 `ecosystem.config.cjs`。
|
|
||||||
2. 在 `env` 里填写 **`JWT_SECRET`**(必填),按需修改 **`UPSTREAM_URL`**。
|
|
||||||
3. 若端口冲突,可在 `args` 中把 `8000` 改成其它端口。
|
|
||||||
|
|
||||||
### 4.2 启动与常用命令
|
|
||||||
|
|
||||||
在项目根目录执行:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cd /www/wwwroot/openai_node
|
||||||
|
source venv/bin/activate
|
||||||
pm2 start ecosystem.config.cjs
|
pm2 start ecosystem.config.cjs
|
||||||
pm2 save
|
pm2 save
|
||||||
|
pm2 status
|
||||||
```
|
```
|
||||||
|
|
||||||
常用运维:
|
常用命令:
|
||||||
|
|
||||||
| 命令 | 作用 |
|
| 命令 | 作用 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `pm2 status` | 查看进程状态 |
|
| `pm2 logs llm-gateway` | 查看日志 |
|
||||||
| `pm2 logs llm-gateway` | 实时日志 |
|
| `pm2 restart llm-gateway` | 重启(改代码/配置后) |
|
||||||
| `pm2 restart llm-gateway` | 重启 |
|
|
||||||
| `pm2 stop llm-gateway` | 停止 |
|
| `pm2 stop llm-gateway` | 停止 |
|
||||||
| `pm2 delete llm-gateway` | 从 PM2 列表移除 |
|
|
||||||
|
|
||||||
修改代码或依赖后:`pip install …` 完成再执行 `pm2 restart llm-gateway`。
|
更新代码后:
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. 不用配置文件时的等价命令
|
|
||||||
|
|
||||||
若暂时不用 `ecosystem.config.cjs`,需自行写出虚拟环境里 **Python 可执行文件绝对路径**。
|
|
||||||
|
|
||||||
**Linux 示例:**
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pm2 start /path/to/中转网关/venv/bin/python \
|
git pull
|
||||||
--name llm-gateway \
|
source venv/bin/activate
|
||||||
--cwd /path/to/中转网关 \
|
pip install -r requirements.txt -U
|
||||||
--interpreter none \
|
pm2 restart llm-gateway
|
||||||
-- -m uvicorn main:app --host 0.0.0.0 --port 8000
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Windows 示例(PowerShell,路径按实际修改):**
|
### 4.3 开机自启
|
||||||
|
|
||||||
```powershell
|
|
||||||
pm2 start "C:\path\to\中转网关\venv\Scripts\python.exe" `
|
|
||||||
--name llm-gateway `
|
|
||||||
--cwd "C:\path\to\中转网关" `
|
|
||||||
--interpreter none `
|
|
||||||
-- -m uvicorn main:app --host 0.0.0.0 --port 8000
|
|
||||||
```
|
|
||||||
|
|
||||||
然后通过 PM2 设置环境变量(任选其一):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pm2 restart llm-gateway --update-env
|
|
||||||
```
|
|
||||||
|
|
||||||
或在启动前于终端导出 `JWT_SECRET`、`UPSTREAM_URL` 后再 `pm2 start …`(注意:`--update-env` 与持久化策略以当前 PM2 版本文档为准)。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. 开机自启
|
|
||||||
|
|
||||||
PM2 保存当前进程列表后,生成并启用开机脚本:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pm2 save
|
pm2 save
|
||||||
pm2 startup
|
pm2 startup
|
||||||
|
# 按提示执行输出的 sudo 命令
|
||||||
```
|
```
|
||||||
|
|
||||||
终端会打印一行以 `sudo` 开头的命令,**复制执行**即可完成 systemd(Linux)或对应平台的自启配置。Windows 可使用 **pm2-windows-service** 或任务计划程序配合 `pm2 resurrect`,按环境选用。
|
---
|
||||||
|
|
||||||
|
## 5. 宝塔反向代理
|
||||||
|
|
||||||
|
### 5.1 添加站点
|
||||||
|
|
||||||
|
宝塔 → **网站** → 添加站点 → 绑定域名 → 申请 **SSL**(Let’s Encrypt)。
|
||||||
|
|
||||||
|
### 5.2 反向代理到 8150
|
||||||
|
|
||||||
|
网站 → **设置** → **反向代理** → 添加:
|
||||||
|
|
||||||
|
| 项 | 值 |
|
||||||
|
|----|-----|
|
||||||
|
| 目标 URL | `http://127.0.0.1:8150` |
|
||||||
|
| 发送域名 | `$host` |
|
||||||
|
|
||||||
|
在 **配置文件** 或「高级」中建议补充(流式 LLM 必备):
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8150;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
说明:
|
||||||
|
|
||||||
|
- `X-Forwarded-For` / `X-Real-IP` 用于网关 **流量统计** 记录真实客户端 IP。
|
||||||
|
- `proxy_buffering off` 与长超时避免流式输出卡顿或中断。
|
||||||
|
|
||||||
|
### 5.3 验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -I https://你的域名/
|
||||||
|
```
|
||||||
|
|
||||||
|
应返回 200。登录 Web → 首页查看模型卡片状态。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. 日志与配置文件
|
## 6. frp 多机穿透(示例)
|
||||||
|
|
||||||
| 项 | 说明 |
|
以下为常见做法,按你实际 frp 版本调整。
|
||||||
|
|
||||||
|
### 6.1 VPS 运行 frps
|
||||||
|
|
||||||
|
`/etc/frp/frps.toml` 示例:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
bindPort = 7000
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 各 PC 运行 frpc
|
||||||
|
|
||||||
|
`/etc/frp/frpc.toml` 示例(书房电脑,本地 Ollama 3313):
|
||||||
|
|
||||||
|
```toml
|
||||||
|
serverAddr = "VPS公网IP"
|
||||||
|
serverPort = 7000
|
||||||
|
|
||||||
|
[[proxies]]
|
||||||
|
name = "ollama-pc1"
|
||||||
|
type = "tcp"
|
||||||
|
localIP = "127.0.0.1"
|
||||||
|
localPort = 3313
|
||||||
|
remotePort = 3313
|
||||||
|
```
|
||||||
|
|
||||||
|
其它电脑分别映射 **3314、3315** … 到 VPS 的 **3314、3315**。
|
||||||
|
|
||||||
|
### 6.3 在 VPS 上验证
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:3313/v1/models
|
||||||
|
curl http://127.0.0.1:3314/v1/models
|
||||||
|
```
|
||||||
|
|
||||||
|
均正常后,在 Web **系统设置** 中为对应节点点击 **测试**,或等待首页健康检查(约 30 秒)变为 **空闲**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Ollama 侧注意
|
||||||
|
|
||||||
|
1. Ollama 需监听 `0.0.0.0` 或 frp 能访问的地址(仅内网/frp,勿公网裸露)。
|
||||||
|
2. API 请求中的 `model` 使用 `ollama list` 中的名称,与 `nodes.json` 一致。
|
||||||
|
3. 流式统计 Token 依赖响应中的 `usage`;可在请求中加 OpenAI 兼容参数(若上游支持):
|
||||||
|
|
||||||
|
```json
|
||||||
|
"stream_options": { "include_usage": true }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 客户端接入
|
||||||
|
|
||||||
|
| 项 | 值 |
|
||||||
|
|----|-----|
|
||||||
|
| Base URL | `https://你的域名/v1` |
|
||||||
|
| API Key | `gateway.json` 的 `api_key` 或用户中心复制 |
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl https://你的域名/v1/chat/completions \
|
||||||
|
-H "Authorization: Bearer sk-你的密钥" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"model":"qwen2.5:14b","messages":[{"role":"user","content":"hi"}]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 运维与数据文件
|
||||||
|
|
||||||
|
| 路径 | 说明 | 备份 |
|
||||||
|
|------|------|------|
|
||||||
|
| `gateway.json` | 账号、API Key | 建议 |
|
||||||
|
| `nodes.json` | 节点与模型 | 建议 |
|
||||||
|
| `gateway_stats.db` | 访问与 Token 统计 | 可选 |
|
||||||
|
| `~/.pm2/logs/` | PM2 日志 | 按需 |
|
||||||
|
|
||||||
|
修改 `nodes.json` 或 Web 设置后,**PM2 会自动读入**(`save_nodes_config` 热加载);若仅改环境变量需 `pm2 restart`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 故障排查
|
||||||
|
|
||||||
|
| 现象 | 排查 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| PM2 日志 | `pm2 logs llm-gateway`,默认在 `~/.pm2/logs/` |
|
| 首页卡片 **离线** | VPS 上 `curl 127.0.0.1:端口/v1/models`;检查 frp、Ollama 是否启动 |
|
||||||
| 账号与 API Key | **`gateway.json`**(或 `GATEWAY_CONFIG` 指向的文件),含明文密码,请限制权限(如 `chmod 600`),勿提交到版本库 |
|
| **404 未找到模型** | 请求 `model` 与 `nodes.json` 中 `models[].id` 不一致 |
|
||||||
|
| **502 上游连接失败** | 端口错、frp 断、防火墙;`pm2 logs llm-gateway` |
|
||||||
|
| 统计 IP 全是 VPS | 宝塔未传 `X-Forwarded-For`,见 §5.2 |
|
||||||
|
| Token 始终为 0 | 上游未返回 `usage`;流式需 `include_usage` |
|
||||||
|
| 改 `JWT_SECRET` 后无法进设置 | 重新登录 Web |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. 反向代理(可选)
|
## 11. 部署检查清单
|
||||||
|
|
||||||
对外只暴露 443/80 时,可用 Nginx/Caddy 把域名反向代理到 `http://127.0.0.1:8000`,并配置 TLS。此时上游 **`UPSTREAM_URL`** 仍指向本机大模型地址,与网关对外端口无关。
|
- [ ] `gateway.json`、`nodes.json` 已配置且权限 `600`
|
||||||
|
- [ ] `JWT_SECRET` 已修改
|
||||||
|
- [ ] PM2 进程 `llm-gateway` 在线,端口 **8150**
|
||||||
|
- [ ] 宝塔 HTTPS 反代到 `127.0.0.1:8150`,流式相关 Nginx 参数已加
|
||||||
|
- [ ] frp 映射 3313+ 在 VPS 本机 `curl` 通过
|
||||||
|
- [ ] 首页模型卡片状态为 **空闲** 或 **忙碌**(非长期离线)
|
||||||
|
- [ ] API 试调用成功,`/stats` 有记录
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. 故障排查
|
## 12. 相关文档
|
||||||
|
|
||||||
1. **`pm2 logs` 中报 ModuleNotFoundError**
|
- 功能与配置总览:[README.md](./README.md)
|
||||||
确认 PM2 使用的解释器是 **`venv` 内的 python**,且已在同一 venv 中执行 `pip install -r requirements.txt`。
|
- 仓库地址:[https://git.bz121.com/dekun/openai_node.git](https://git.bz121.com/dekun/openai_node.git)
|
||||||
|
|
||||||
2. **502 / 上游连接失败**
|
|
||||||
检查大模型是否监听 `UPSTREAM_URL`,防火墙与内网穿透是否正常。
|
|
||||||
|
|
||||||
3. **修改 `JWT_SECRET` 后旧登录失效**
|
|
||||||
属预期行为,用户需重新登录网页端。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. 小结
|
|
||||||
|
|
||||||
1. 创建 venv 并安装 `requirements.txt`。
|
|
||||||
2. 配置 **`JWT_SECRET`**(及可选 **`UPSTREAM_URL`**)。
|
|
||||||
3. `pm2 start ecosystem.config.cjs` → `pm2 save` → `pm2 startup`(按需)。
|
|
||||||
|
|
||||||
进程名 **`llm-gateway`** 与 `ecosystem.config.cjs` 中 `name` 字段一致,便于 `pm2 restart llm-gateway` 等操作。
|
|
||||||
|
|||||||
@@ -0,0 +1,213 @@
|
|||||||
|
# openai_node
|
||||||
|
|
||||||
|
本地 **Ollama / OpenAI 兼容** 大模型中转网关:统一鉴权、多节点按模型调度、Web 管理面板与流量统计。
|
||||||
|
|
||||||
|
代码仓库:[https://git.bz121.com/dekun/openai_node.git](https://git.bz121.com/dekun/openai_node.git)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 功能概览
|
||||||
|
|
||||||
|
| 模块 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **OpenAI 兼容 API** | `POST /v1/chat/completions`,Bearer `sk-...` 鉴权,支持流式响应 |
|
||||||
|
| **多节点调度** | 按请求体中的 `model` 转发到不同机器/端口(`nodes.json`) |
|
||||||
|
| **Web 控制台** | 首页模型分布卡片、流量统计、系统设置、用户中心 |
|
||||||
|
| **访问统计** | 记录客户端 IP、Token 用量、按节点汇总(SQLite) |
|
||||||
|
| **健康检查** | 定时探测各节点 `/v1/models`,首页显示中文状态 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 架构示意
|
||||||
|
|
||||||
|
```
|
||||||
|
客户端 / Cursor / 脚本
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
宝塔 Nginx(443/80)──反代──► VPS :8150(本网关)
|
||||||
|
│ │
|
||||||
|
│ ├─ 鉴权 / 统计 / Web
|
||||||
|
│ │
|
||||||
|
│ ┌────────────┼────────────┐
|
||||||
|
│ ▼ ▼ ▼
|
||||||
|
│ 127.0.0.1:3313 :3314 :3315 …(frp 映射)
|
||||||
|
│ │ │ │
|
||||||
|
│ PC-A Ollama PC-B Ollama PC-C Ollama
|
||||||
|
```
|
||||||
|
|
||||||
|
- **对外只暴露一个域名**,反代到网关 **8150**。
|
||||||
|
- 各家用/办公室电脑通过 **frp** 等内网穿透,把模型端口映射到 VPS 本机 `127.0.0.1:3313` 等。
|
||||||
|
- 网关在 **系统设置** 中维护「端口 ↔ 模型」关系,无需为每台机器单独配公网域名。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
- Python **3.10+**
|
||||||
|
- 上游服务:**Ollama**(或其它 OpenAI 兼容 HTTP API)
|
||||||
|
- 生产建议:**PM2** 守护进程;**宝塔** 或 Nginx 做 HTTPS 反代
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 克隆仓库
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.bz121.com/dekun/openai_node.git
|
||||||
|
cd openai_node
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate # Windows: .\venv\Scripts\Activate.ps1
|
||||||
|
pip install -r requirements.txt -U
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 配置文件
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp gateway.json.example gateway.json
|
||||||
|
cp nodes.json.example nodes.json
|
||||||
|
```
|
||||||
|
|
||||||
|
编辑 **`gateway.json`**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"password": "你的强密码",
|
||||||
|
"api_key": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`api_key` 留空时,首次启动会自动生成 `sk-...` 并写回文件。
|
||||||
|
|
||||||
|
编辑 **`nodes.json`**(示例为 3 台节点,主机默认 `127.0.0.1`,端口 `3313–3315`):
|
||||||
|
|
||||||
|
- `models[].id` 必须与调用 API 时 JSON 里的 **`model` 字段完全一致**(Ollama 模型名)。
|
||||||
|
- `models[].label` 为 Web 卡片上的显示名。
|
||||||
|
|
||||||
|
### 4. 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export JWT_SECRET="请改为长随机字符串"
|
||||||
|
python -m uvicorn main:app --host 0.0.0.0 --port 8150
|
||||||
|
```
|
||||||
|
|
||||||
|
浏览器打开 `http://127.0.0.1:8150`:
|
||||||
|
|
||||||
|
| 路径 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `/` | 首页:模型分布卡片 + 使用说明 |
|
||||||
|
| `/login` | 管理员登录 |
|
||||||
|
| `/settings` | 系统设置(节点/端口/模型,需登录) |
|
||||||
|
| `/stats` | 流量统计、IP 列表、Token 账单 |
|
||||||
|
| `/user` | 查看 / 复制 API Key |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 调用示例
|
||||||
|
|
||||||
|
将 `https://你的域名` 换为实际地址(或 `http://IP:8150` 调试):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl https://你的域名/v1/chat/completions \
|
||||||
|
-H "Authorization: Bearer sk-xxxx" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"model": "your-model-id-1",
|
||||||
|
"messages": [{"role": "user", "content": "你好"}],
|
||||||
|
"stream": true
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
在 Cursor、OpenAI SDK 等客户端中:
|
||||||
|
|
||||||
|
- **Base URL**:`https://你的域名/v1`
|
||||||
|
- **API Key**:`gateway.json` 中的 `api_key` 或用户中心页面复制
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### gateway.json
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `username` | Web 登录用户名 |
|
||||||
|
| `password` | Web 登录密码(明文存储,请限制文件权限) |
|
||||||
|
| `api_key` | OpenAI 兼容 API Key,可自动生成 |
|
||||||
|
|
||||||
|
### nodes.json
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `id` | 节点唯一 ID(系统自动生成亦可) |
|
||||||
|
| `name` | 显示名称 |
|
||||||
|
| `host` | 上游主机,frp 场景填 **`127.0.0.1`** |
|
||||||
|
| `port` | 上游端口,如 **3313–3318** |
|
||||||
|
| `enabled` | 是否启用 |
|
||||||
|
| `max_concurrent` | 单节点最大并发请求数(建议 1) |
|
||||||
|
| `models` | `{ "id": "模型ID", "label": "显示名" }` 列表 |
|
||||||
|
|
||||||
|
也可在 Web **系统设置** 中增删改,保存后写入 `nodes.json`。
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
|
||||||
|
| 变量 | 默认值 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| `JWT_SECRET` | (弱默认值) | **生产必改**,Web 登录 JWT 签名 |
|
||||||
|
| `GATEWAY_PORT` | `8150` | 监听端口 |
|
||||||
|
| `GATEWAY_CONFIG` | `gateway.json` | 账号配置路径 |
|
||||||
|
| `NODES_CONFIG` | `nodes.json` | 节点配置路径 |
|
||||||
|
| `STATS_DB` | `gateway_stats.db` | 统计数据库路径 |
|
||||||
|
| `UPSTREAM_URL` | `http://127.0.0.1:10434` | **未配置 nodes 时** 的单机上流回退地址 |
|
||||||
|
| `APP_ROOT` | 空 | 反代子路径前缀,如 `/wg` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 节点状态(中文)
|
||||||
|
|
||||||
|
| 状态 | 含义 |
|
||||||
|
|------|------|
|
||||||
|
| 空闲 | 在线且可接受新请求 |
|
||||||
|
| 忙碌 | 已达 `max_concurrent` |
|
||||||
|
| 离线 | 健康检查未通过 |
|
||||||
|
| 未启用 | 节点在设置中关闭 |
|
||||||
|
| 异常 | 连接失败并带有错误信息 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目文件
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `main.py` | 网关主程序(API + Web 单文件) |
|
||||||
|
| `gateway.json.example` | 账号配置示例 |
|
||||||
|
| `nodes.json.example` | 多节点配置示例 |
|
||||||
|
| `requirements.txt` | Python 依赖 |
|
||||||
|
| `ecosystem.config.cjs` | PM2 配置 |
|
||||||
|
| `DEPLOY.md` | **生产部署文档**(宝塔 + frp + PM2) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 安全提示
|
||||||
|
|
||||||
|
- 勿将 `gateway.json`、`nodes.json`、`gateway_stats.db` 提交到公开仓库。
|
||||||
|
- 生产环境务必修改 **`JWT_SECRET`**,并为 `gateway.json` 设置严格文件权限(如 `chmod 600`)。
|
||||||
|
- 统计与设置接口需 Web 登录;API 调用使用 `sk-` Key,请勿混用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 生产部署
|
||||||
|
|
||||||
|
详见 **[DEPLOY.md](./DEPLOY.md)**(VPS、宝塔反代 8150、frp 多机、PM2)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
私有仓库,按团队内部约定使用。
|
||||||
Reference in New Issue
Block a user