first commit
This commit is contained in:
@@ -0,0 +1,181 @@
|
|||||||
|
# LLM 中转网关 · PM2 部署说明
|
||||||
|
|
||||||
|
本文说明如何在服务器上使用 **PM2** 守护 **FastAPI(uvicorn)** 进程,实现崩溃自动拉起、开机自启与日志管理。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 前置条件
|
||||||
|
|
||||||
|
| 组件 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| **Python** | 建议 3.10+,已加入 `PATH` |
|
||||||
|
| **Node.js** | 用于安装 PM2(LTS 即可) |
|
||||||
|
| **PM2** | `npm i -g pm2` |
|
||||||
|
| **本项目** | 含 `main.py`、`requirements.txt`,可选 `ecosystem.config.cjs` |
|
||||||
|
|
||||||
|
上游本地大模型(默认 `http://127.0.0.1:10434`)需在同一台机器或内网可达;若在大模型同一主机部署网关,确保端口未被占用(下文示例为 **8000**)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 准备运行环境
|
||||||
|
|
||||||
|
在 **项目根目录**(与 `main.py` 同级)执行:
|
||||||
|
|
||||||
|
### Linux / macOS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/中转网关
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt -U
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows(PowerShell)
|
||||||
|
|
||||||
|
```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
|
||||||
|
python -m uvicorn main:app --host 0.0.0.0 --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
浏览器访问 `http://服务器IP:8000` 正常后再交给 PM2。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 环境变量(生产必改)
|
||||||
|
|
||||||
|
| 变量 | 含义 | 建议 |
|
||||||
|
|------|------|------|
|
||||||
|
| `JWT_SECRET` | 签发网页登录 JWT 的密钥 | 长随机字符串,勿泄露 |
|
||||||
|
| `UPSTREAM_URL` | 上游 OpenAI 兼容服务根地址(无末尾 `/`) | 默认 `http://127.0.0.1:10434`,按实际修改 |
|
||||||
|
|
||||||
|
可在 shell 中导出,或在 PM2 的 `env` / `ecosystem.config.cjs` 中配置(见下文)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 使用 PM2 启动(推荐 ecosystem)
|
||||||
|
|
||||||
|
项目根目录已提供 **`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
|
||||||
|
pm2 start ecosystem.config.cjs
|
||||||
|
pm2 save
|
||||||
|
```
|
||||||
|
|
||||||
|
常用运维:
|
||||||
|
|
||||||
|
| 命令 | 作用 |
|
||||||
|
|------|------|
|
||||||
|
| `pm2 status` | 查看进程状态 |
|
||||||
|
| `pm2 logs llm-gateway` | 实时日志 |
|
||||||
|
| `pm2 restart llm-gateway` | 重启 |
|
||||||
|
| `pm2 stop llm-gateway` | 停止 |
|
||||||
|
| `pm2 delete llm-gateway` | 从 PM2 列表移除 |
|
||||||
|
|
||||||
|
修改代码或依赖后:`pip install …` 完成再执行 `pm2 restart llm-gateway`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 不用配置文件时的等价命令
|
||||||
|
|
||||||
|
若暂时不用 `ecosystem.config.cjs`,需自行写出虚拟环境里 **Python 可执行文件绝对路径**。
|
||||||
|
|
||||||
|
**Linux 示例:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pm2 start /path/to/中转网关/venv/bin/python \
|
||||||
|
--name llm-gateway \
|
||||||
|
--cwd /path/to/中转网关 \
|
||||||
|
--interpreter none \
|
||||||
|
-- -m uvicorn main:app --host 0.0.0.0 --port 8000
|
||||||
|
```
|
||||||
|
|
||||||
|
**Windows 示例(PowerShell,路径按实际修改):**
|
||||||
|
|
||||||
|
```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
|
||||||
|
pm2 save
|
||||||
|
pm2 startup
|
||||||
|
```
|
||||||
|
|
||||||
|
终端会打印一行以 `sudo` 开头的命令,**复制执行**即可完成 systemd(Linux)或对应平台的自启配置。Windows 可使用 **pm2-windows-service** 或任务计划程序配合 `pm2 resurrect`,按环境选用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 日志与配置文件
|
||||||
|
|
||||||
|
| 项 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| PM2 日志 | `pm2 logs llm-gateway`,默认在 `~/.pm2/logs/` |
|
||||||
|
| 账号与 API Key | **`gateway.json`**(或 `GATEWAY_CONFIG` 指向的文件),含明文密码,请限制权限(如 `chmod 600`),勿提交到版本库 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 反向代理(可选)
|
||||||
|
|
||||||
|
对外只暴露 443/80 时,可用 Nginx/Caddy 把域名反向代理到 `http://127.0.0.1:8000`,并配置 TLS。此时上游 **`UPSTREAM_URL`** 仍指向本机大模型地址,与网关对外端口无关。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 故障排查
|
||||||
|
|
||||||
|
1. **`pm2 logs` 中报 ModuleNotFoundError**
|
||||||
|
确认 PM2 使用的解释器是 **`venv` 内的 python**,且已在同一 venv 中执行 `pip install -r requirements.txt`。
|
||||||
|
|
||||||
|
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,35 @@
|
|||||||
|
/**
|
||||||
|
* PM2 进程配置:在项目根目录执行 pm2 start ecosystem.config.cjs
|
||||||
|
* 请先创建 venv 并 pip install -r requirements.txt
|
||||||
|
*/
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const isWin = process.platform === "win32";
|
||||||
|
const py = isWin
|
||||||
|
? path.join(__dirname, "venv", "Scripts", "python.exe")
|
||||||
|
: path.join(__dirname, "venv", "bin", "python");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: "llm-gateway",
|
||||||
|
cwd: __dirname,
|
||||||
|
interpreter: "none",
|
||||||
|
script: py,
|
||||||
|
args: "-m uvicorn main:app --host 0.0.0.0 --port 8150",
|
||||||
|
instances: 1,
|
||||||
|
autorestart: true,
|
||||||
|
watch: false,
|
||||||
|
max_memory_restart: "500M",
|
||||||
|
env: {
|
||||||
|
NODE_ENV: "production",
|
||||||
|
// 非 TTY 下避免 stdout/stderr 被缓冲,否则 pm2 logs 长时间看不到输出
|
||||||
|
PYTHONUNBUFFERED: "1",
|
||||||
|
// 生产环境务必改为足够长的随机字符串
|
||||||
|
JWT_SECRET: "change-me-to-a-long-random-secret",
|
||||||
|
GATEWAY_PORT: "8150",
|
||||||
|
UPSTREAM_URL: "http://127.0.0.1:10434",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"username": "admin",
|
||||||
|
"password": "请修改为强密码",
|
||||||
|
"api_key": ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": "node-1",
|
||||||
|
"name": "节点 1",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 3313,
|
||||||
|
"enabled": true,
|
||||||
|
"max_concurrent": 1,
|
||||||
|
"models": [
|
||||||
|
{ "id": "your-model-id-1", "label": "模型显示名 1" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node-2",
|
||||||
|
"name": "节点 2",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 3314,
|
||||||
|
"enabled": true,
|
||||||
|
"max_concurrent": 1,
|
||||||
|
"models": [
|
||||||
|
{ "id": "your-model-id-2", "label": "模型显示名 2" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "node-3",
|
||||||
|
"name": "节点 3",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 3315,
|
||||||
|
"enabled": true,
|
||||||
|
"max_concurrent": 1,
|
||||||
|
"models": [
|
||||||
|
{ "id": "your-model-id-3", "label": "模型显示名 3" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
typing_extensions>=4.5.0
|
||||||
|
fastapi>=0.110.0
|
||||||
|
uvicorn[standard]>=0.27.0
|
||||||
|
passlib[bcrypt]>=1.7.4
|
||||||
|
bcrypt>=4.0.0,<5.0.0
|
||||||
|
python-jose[cryptography]>=3.3.0
|
||||||
|
httpx>=0.27.0
|
||||||
Reference in New Issue
Block a user