# openai_node · 生产部署文档(Ubuntu) 本文说明如何在 **Ubuntu VPS** 上以 **root** 用户部署本网关,安装目录 **`/opt/openai_node`**,并通过 **宝塔面板** 反向代理、**frp** 汇聚多台本地 Ollama 节点。 | 项 | 约定 | |----|------| | 系统 | Ubuntu 22.04 / 24.04 | | 用户 | **root** | | 安装路径 | **`/opt/openai_node`** | | 网关端口 | **8150** | | 宝塔反代 | 域名 → `http://127.0.0.1:8150` | | 模型端口 | **3313–3318**(frp 映射到本机 `127.0.0.1`) | 代码仓库:[https://git.bz121.com/dekun/openai_node.git](https://git.bz121.com/dekun/openai_node.git) --- ## 1. 部署拓扑 ``` Internet │ ▼ ┌─────────────────┐ │ Ubuntu VPS │ │ 宝塔 Nginx:443 │ │ │ │ │ ▼ │ │ /opt/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 等端口直接暴露到公网,仅本机 `127.0.0.1` 访问。 2. **不要**让宝塔直接把域名反代到各 PC;应只反代到 **8150**,由网关按 `model` 调度。 3. `nodes.json` 里 `host` 填 **`127.0.0.1`**,`port` 填 frp 映射后的端口。 --- ## 2. 前置条件 以 **root** 登录 VPS 后,安装基础组件: ```bash apt update apt install -y python3 python3-venv python3-pip git curl ``` | 组件 | 版本建议 | 用途 | |------|----------|------| | Python | **3.8+**(推荐 3.10+;`python3 -V` 确认) | 运行网关 | | Node.js | LTS | 安装 PM2 | | PM2 | 最新 | 进程守护 | | 宝塔 | 7.x+ | Nginx 反代、SSL | | frp | 客户端 + 服务端 | 内网穿透 | 安装 Node.js 与 PM2: ```bash curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - apt install -y nodejs npm install -g pm2 ``` 各 PC 已安装 **Ollama** 并监听本地端口(如 3313),且通过 frp 与 VPS 连通。 --- ## 3. 部署网关到 /opt/openai_node 以下命令均在 **root** 下执行。 ### 3.1 克隆代码 ```bash cd /opt git clone https://git.bz121.com/dekun/openai_node.git cd /opt/openai_node ``` 若目录已存在,更新代码: ```bash cd /opt/openai_node git pull ``` ### 3.2 虚拟环境与依赖 ```bash cd /opt/openai_node python3 -m venv venv source venv/bin/activate pip install -r requirements.txt -U # 若曾装过新版 bcrypt 导致 passlib 报错,可强制重装: # pip install 'bcrypt>=4.0.0,<4.1.0' -U --force-reinstall ``` ### 3.3 配置文件 ```bash cd /opt/openai_node cp gateway.json.example gateway.json cp nodes.json.example nodes.json chmod 600 gateway.json nodes.json ``` 编辑 **`/opt/openai_node/gateway.json`**:设置 `username`、`password`;`api_key` 可留空自动生成。 编辑 **`/opt/openai_node/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 环境变量 在 **`/opt/openai_node/ecosystem.config.cjs`** 的 `env` 中配置(推荐),或导出后启动: | 变量 | 生产建议 | |------|----------| | `JWT_SECRET` | **必改**,长随机字符串 | | `GATEWAY_PORT` | `8150` | 可选: | 变量 | 说明 | |------|------| | `STATS_DB` | 默认 `/opt/openai_node/gateway_stats.db` | | `NODES_CONFIG` | 默认 `/opt/openai_node/nodes.json` | | `GATEWAY_CONFIG` | 默认 `/opt/openai_node/gateway.json` | ### 3.5 手动试跑 ```bash cd /opt/openai_node source venv/bin/activate 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`,首页应出现模型卡片。确认无误后 `Ctrl+C` 停止,改由 PM2 守护。 --- ## 4. PM2 守护 项目 **`/opt/openai_node/ecosystem.config.cjs`** 已配置端口 **8150** 与 venv 内 Python 路径。 ### 4.1 修改 PM2 配置 ```bash nano /opt/openai_node/ecosystem.config.cjs ``` 将 `env.JWT_SECRET` 改为生产密钥。 ### 4.2 启动 ```bash cd /opt/openai_node pm2 start ecosystem.config.cjs pm2 save pm2 status ``` 应看到进程名 **`llm-gateway`** 为 `online`。 常用命令: | 命令 | 作用 | |------|------| | `pm2 logs llm-gateway` | 查看日志 | | `pm2 restart llm-gateway` | 重启 | | `pm2 stop llm-gateway` | 停止 | 更新代码后: ```bash cd /opt/openai_node git pull source venv/bin/activate pip install -r requirements.txt -U pm2 restart llm-gateway ``` ### 4.3 开机自启(root) ```bash pm2 save pm2 startup ``` **root** 用户下,终端会打印一行命令(通常已含 `systemd` 配置),**直接复制执行**即可,一般无需再加 `sudo`。 验证: ```bash systemctl status pm2-root # 服务名以 pm2 实际输出为准 ``` --- ## 5. 宝塔反向代理 ### 5.1 添加站点 宝塔 → **网站** → 添加站点 → 绑定域名 → 申请 **SSL**。 ### 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; } ``` ### 5.3 验证 ```bash curl -I https://你的域名/ ``` 登录 Web → 首页查看模型卡片。 --- ## 6. frp 多机穿透(示例) ### 6.1 VPS(root)运行 frps ```bash mkdir -p /etc/frp nano /etc/frp/frps.toml ``` ```toml bindPort = 7000 ``` 按需配置 systemd 开机启动 frps。 ### 6.2 各 PC 运行 frpc ```toml serverAddr = "VPS公网IP" serverPort = 7000 [[proxies]] name = "ollama-pc1" type = "tcp" localIP = "127.0.0.1" localPort = 3313 remotePort = 3313 ``` 其它电脑映射 **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 监听地址需能被 frp 访问(勿将模型端口裸露公网)。 2. API 中 `model` 与 `nodes.json` / `ollama list` 名称一致。 3. 流式 Token 统计(可选): ```json "stream_options": { "include_usage": true } ``` --- ## 8. 客户端接入 | 项 | 值 | |----|-----| | Base URL | `https://你的域名/v1` | | API Key | `/opt/openai_node/gateway.json` 或用户中心复制 | ```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. 运维与数据文件 | 路径 | 说明 | 备份 | |------|------|------| | `/opt/openai_node/gateway.json` | 账号、API Key | 建议 | | `/opt/openai_node/nodes.json` | 节点与模型 | 建议 | | `/opt/openai_node/gateway_stats.db` | 访问与 Token 统计 | 可选 | | `/root/.pm2/logs/` | PM2 日志 | 按需 | Web 保存节点配置会写入 `nodes.json` 并热加载;仅改 `ecosystem.config.cjs` 环境变量时需 `pm2 restart llm-gateway`。 --- ## 10. 故障排查 | 现象 | 排查 | |------|------| | 首页卡片 **离线** | `curl http://127.0.0.1:端口/v1/models`;frp、Ollama | | **404 未找到模型** | 请求 `model` 与 `nodes.json` 中 `id` 不一致 | | **502 上游连接失败** | `pm2 logs llm-gateway`;端口与 frp | | 统计 IP 不对 | 宝塔是否传递 `X-Forwarded-For`(§5.2) | | Token 为 0 | 上游 `usage`;流式 `include_usage` | | PM2 找不到模块 | 确认使用 `/opt/openai_node/venv` 内 Python | | `asyncio` 无 `to_thread` | Python 3.8:拉最新代码(已用 `run_in_thread` 兼容) | | bcrypt `__about__` 报错 | `pip install 'bcrypt>=4.0.0,<4.1.0' -U --force-reinstall` 后重启 PM2 | --- ## 11. 部署检查清单 - [ ] 以 **root** 部署,代码在 **`/opt/openai_node`** - [ ] `gateway.json`、`nodes.json` 已配置,`chmod 600` - [ ] `JWT_SECRET` 已在 `ecosystem.config.cjs` 中修改 - [ ] `pm2 status` 中 **llm-gateway** 在线,监听 **8150** - [ ] 宝塔 HTTPS 反代到 `127.0.0.1:8150`,Nginx 流式参数已加 - [ ] frp 映射端口在本机 `curl` 通过 - [ ] 首页模型卡片非长期 **离线** - [ ] API 试调用成功 --- ## 12. 相关文档 - [README.md](./README.md) - 仓库:[https://git.bz121.com/dekun/openai_node.git](https://git.bz121.com/dekun/openai_node.git)