344 lines
8.6 KiB
Markdown
344 lines
8.6 KiB
Markdown
# openai_node · 生产部署文档
|
||
|
||
本文说明如何在 **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. 部署拓扑
|
||
|
||
```
|
||
Internet
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ 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
|
||
└─────────────────┘
|
||
```
|
||
|
||
要点:
|
||
|
||
1. **不要**把 3313 等端口直接暴露到公网,仅 VPS 本机访问。
|
||
2. **不要**让宝塔直接把域名反代到各 PC;应只反代到 **8150**,由网关按 `model` 调度。
|
||
3. `nodes.json` 里 `host` 填 **`127.0.0.1`**,`port` 填 frp 映射后的端口。
|
||
|
||
---
|
||
|
||
## 2. 前置条件
|
||
|
||
| 组件 | 版本建议 | 用途 |
|
||
|------|----------|------|
|
||
| Python | 3.10+ | 运行网关 |
|
||
| Node.js | LTS | 安装 PM2 |
|
||
| PM2 | 最新 | 进程守护 |
|
||
| 宝塔 | 7.x+ | Nginx 反代、SSL |
|
||
| frp | 客户端 + 服务端 | 内网穿透(可用其它方案,原理相同) |
|
||
|
||
各 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
|
||
python3 -m venv venv
|
||
source venv/bin/activate
|
||
pip install -r requirements.txt -U
|
||
```
|
||
|
||
### 3.3 配置文件
|
||
|
||
```bash
|
||
cp gateway.json.example gateway.json
|
||
cp nodes.json.example nodes.json
|
||
chmod 600 gateway.json nodes.json
|
||
```
|
||
|
||
编辑 **`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`,首页应出现模型卡片。
|
||
|
||
---
|
||
|
||
## 4. PM2 守护
|
||
|
||
项目已包含 **`ecosystem.config.cjs`**(端口 **8150**)。
|
||
|
||
### 4.1 修改 PM2 配置
|
||
|
||
编辑 `ecosystem.config.cjs` 中 `env.JWT_SECRET` 为生产密钥。
|
||
|
||
### 4.2 启动
|
||
|
||
```bash
|
||
cd /www/wwwroot/openai_node
|
||
source venv/bin/activate
|
||
pm2 start ecosystem.config.cjs
|
||
pm2 save
|
||
pm2 status
|
||
```
|
||
|
||
常用命令:
|
||
|
||
| 命令 | 作用 |
|
||
|------|------|
|
||
| `pm2 logs llm-gateway` | 查看日志 |
|
||
| `pm2 restart llm-gateway` | 重启(改代码/配置后) |
|
||
| `pm2 stop llm-gateway` | 停止 |
|
||
|
||
更新代码后:
|
||
|
||
```bash
|
||
git pull
|
||
source venv/bin/activate
|
||
pip install -r requirements.txt -U
|
||
pm2 restart llm-gateway
|
||
```
|
||
|
||
### 4.3 开机自启
|
||
|
||
```bash
|
||
pm2 save
|
||
pm2 startup
|
||
# 按提示执行输出的 sudo 命令
|
||
```
|
||
|
||
---
|
||
|
||
## 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 → 首页查看模型卡片状态。
|
||
|
||
---
|
||
|
||
## 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. 故障排查
|
||
|
||
| 现象 | 排查 |
|
||
|------|------|
|
||
| 首页卡片 **离线** | VPS 上 `curl 127.0.0.1:端口/v1/models`;检查 frp、Ollama 是否启动 |
|
||
| **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 |
|
||
|
||
---
|
||
|
||
## 11. 部署检查清单
|
||
|
||
- [ ] `gateway.json`、`nodes.json` 已配置且权限 `600`
|
||
- [ ] `JWT_SECRET` 已修改
|
||
- [ ] PM2 进程 `llm-gateway` 在线,端口 **8150**
|
||
- [ ] 宝塔 HTTPS 反代到 `127.0.0.1:8150`,流式相关 Nginx 参数已加
|
||
- [ ] frp 映射 3313+ 在 VPS 本机 `curl` 通过
|
||
- [ ] 首页模型卡片状态为 **空闲** 或 **忙碌**(非长期离线)
|
||
- [ ] API 试调用成功,`/stats` 有记录
|
||
|
||
---
|
||
|
||
## 12. 相关文档
|
||
|
||
- 功能与配置总览:[README.md](./README.md)
|
||
- 仓库地址:[https://git.bz121.com/dekun/openai_node.git](https://git.bz121.com/dekun/openai_node.git)
|