481 lines
12 KiB
Markdown
481 lines
12 KiB
Markdown
# Goal Planner Linux 部署指南
|
||
|
||
## 环境要求
|
||
|
||
### 服务器
|
||
- Linux 服务器(Ubuntu 20.04+ / CentOS 7+)
|
||
- Python 3.11+(由 uv 管理,不依赖系统 Python)
|
||
- MySQL 5.7+ / 8.0(需提前安装)
|
||
- Nginx(需提前安装)
|
||
- [uv](https://docs.astral.sh/uv/)(Python 包管理工具)
|
||
|
||
> **关于 Python 版本**:项目要求 Python ≥ 3.10。CentOS 7 系统自带 Python 2.7.5,无需升级或卸载,uv 会自动下载和管理独立的 Python 版本,不会与系统 Python 冲突。系统工具(如 yum)依赖的 Python 2.7.5 完全不受影响。**推荐使用 Python 3.11**,wheel 生态最成熟,所有依赖都有预编译 wheel,安装秒完成;Python 3.12/3.14 部分包(如 greenlet、pydantic-core)在 CentOS 7 上缺少兼容的预编译 wheel,需要从源码编译,而 CentOS 7 的 GCC 4.8.5 不支持 C++11,会导致编译失败。
|
||
|
||
### 本地(仅构建前端时需要)
|
||
- Node.js 18+
|
||
|
||
---
|
||
|
||
## 1. 安装 uv
|
||
|
||
```bash
|
||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||
```
|
||
|
||
安装完成后,需要让 uv 命令生效(二选一):
|
||
|
||
```bash
|
||
# 方式一:执行以下命令(推荐,立即生效)
|
||
source $HOME/.local/bin/env
|
||
|
||
# 方式二:重新连接 SSH
|
||
```
|
||
|
||
验证安装:
|
||
|
||
```bash
|
||
uv --version
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 配置 MySQL
|
||
|
||
```bash
|
||
# 登录 MySQL
|
||
sudo mysql -u root -p
|
||
|
||
# 创建数据库和用户
|
||
CREATE DATABASE goal_planner CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
CREATE USER 'goal_planner'@'localhost' IDENTIFIED BY '你的数据库密码';
|
||
GRANT ALL PRIVILEGES ON goal_planner.* TO 'goal_planner'@'localhost';
|
||
FLUSH PRIVILEGES;
|
||
EXIT;
|
||
```
|
||
|
||
> 首次启动后端时,SQLAlchemy 会自动创建表结构,无需手动导入。
|
||
|
||
---
|
||
|
||
## 3. 上传项目
|
||
|
||
将项目上传到服务器,部署目录为 `/home/wwwroot/goal-planner`:
|
||
|
||
```bash
|
||
sudo mkdir -p /home/wwwroot/goal-planner
|
||
# 方式一:git clone
|
||
cd /home/wwwroot/goal-planner
|
||
git clone <你的仓库地址> .
|
||
|
||
# 方式二:scp 上传
|
||
# scp -r ./goal-planner/* user@server:/home/wwwroot/goal-planner/
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 后端部署
|
||
|
||
### 4.1 配置环境变量
|
||
|
||
```bash
|
||
cd /home/wwwroot/goal-planner/backend
|
||
cp .env.example .env
|
||
```
|
||
|
||
编辑 `.env` 文件:
|
||
|
||
```bash
|
||
vi .env
|
||
```
|
||
|
||
填入实际配置:
|
||
|
||
```env
|
||
MYSQL_HOST=localhost
|
||
MYSQL_PORT=3306
|
||
MYSQL_USER=goal_planner
|
||
MYSQL_PASSWORD=你的数据库密码
|
||
MYSQL_DATABASE=goal_planner
|
||
SECRET_KEY=替换为一个随机长字符串
|
||
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
||
LLM_PROVIDER=dashscope
|
||
OPENAI_API_KEY=你的API密钥
|
||
OPENAI_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
|
||
OPENAI_MODEL=qwen3-plus
|
||
ENABLE_SEARCH=true
|
||
```
|
||
|
||
> **重要**:`SECRET_KEY` 必须替换为随机字符串,可用 `openssl rand -hex 32` 生成。
|
||
|
||
### 4.2 使用 uv 创建虚拟环境并安装依赖
|
||
|
||
```bash
|
||
cd /home/wwwroot/goal-planner
|
||
|
||
# 创建虚拟环境,uv 会自动下载 Python 3.11(不依赖系统 Python)
|
||
uv venv .venv --python 3.11
|
||
|
||
# 激活虚拟环境
|
||
source .venv/bin/activate
|
||
|
||
# 安装依赖(使用清华镜像加速,强制只安装预编译 wheel)
|
||
uv pip install -r backend/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple --only-binary :all:
|
||
```
|
||
|
||
> **说明**:`uv venv --python 3.11` 会将 Python 3.11 下载到 `~/.local/share/uv/python/` 目录,仅 uv 使用,不会覆盖或修改系统自带的 Python 2.7.5。虚拟环境放在项目根目录 `/home/wwwroot/goal-planner/.venv`,与 backend 同级。`--only-binary :all:` 强制只安装预编译 wheel,避免在 CentOS 7 的旧 GCC 上从源码编译失败。
|
||
|
||
### 4.3 验证后端启动
|
||
|
||
```bash
|
||
cd /home/wwwroot/goal-planner/backend
|
||
source /home/wwwroot/goal-planner/.venv/bin/activate
|
||
uvicorn main:app --host 127.0.0.1 --port 8000
|
||
```
|
||
|
||
看到 `Uvicorn running on http://127.0.0.1:8000` 即启动成功,`Ctrl+C` 停止。
|
||
|
||
### 4.4 后台运行
|
||
|
||
验证无误后,使用以下方式后台运行(推荐方式二):
|
||
|
||
**方式一:nohup(简单快速)**
|
||
|
||
```bash
|
||
cd /home/wwwroot/goal-planner/backend
|
||
source /home/wwwroot/goal-planner/.venv/bin/activate
|
||
nohup uvicorn main:app --host 127.0.0.1 --port 8000 > /home/wwwroot/goal-planner/backend/app.log 2>&1 &
|
||
```
|
||
|
||
常用操作:
|
||
|
||
```bash
|
||
# 查看日志
|
||
tail -f /home/wwwroot/goal-planner/backend/app.log
|
||
|
||
# 查看进程
|
||
ps aux | grep uvicorn
|
||
|
||
# 停止服务
|
||
kill $(ps aux | grep 'uvicorn main:app' | grep -v grep | awk '{print $2}')
|
||
```
|
||
|
||
**方式二:systemd 服务(推荐,开机自启 + 自动重启)**
|
||
|
||
见第 7 章。
|
||
|
||
---
|
||
|
||
## 5. 前端构建与部署
|
||
|
||
### 5.1 修改 API 接口地址
|
||
|
||
前端 API 地址硬编码在 `frontend/services/apiService.ts` 中:
|
||
|
||
```typescript
|
||
const API_BASE_URL = 'http://localhost:8000';
|
||
```
|
||
|
||
**部署前必须修改为实际的后端地址**。根据你的部署方式选择:
|
||
|
||
#### 方式一:使用 Nginx 反向代理(推荐)
|
||
|
||
将 API 地址改为相对路径,由 Nginx 统一代理:
|
||
|
||
```typescript
|
||
const API_BASE_URL = '/api-proxy';
|
||
```
|
||
|
||
这样前端请求 `/api-proxy/api/generate/` 会被 Nginx 转发到后端 `http://127.0.0.1:8000/api/generate/`,无需暴露后端端口。
|
||
|
||
#### 方式二:直接指向后端地址
|
||
|
||
如果你的后端运行在独立域名或端口上:
|
||
|
||
```typescript
|
||
const API_BASE_URL = 'http://你的服务器IP:8000';
|
||
```
|
||
|
||
> **注意**:此方式需要后端开放 8000 端口,并在 `main.py` 的 CORS 配置中添加前端域名。
|
||
|
||
### 5.2 修改后端 CORS 配置(方式一不需要)
|
||
|
||
如果使用方式二,需要修改 `backend/main.py` 中的 CORS 允许来源:
|
||
|
||
```python
|
||
origins = [
|
||
"http://你的域名",
|
||
"http://你的服务器IP",
|
||
]
|
||
```
|
||
|
||
### 5.3 本地构建前端
|
||
|
||
在本地开发机器上执行构建(不需要在服务器上安装 Node.js):
|
||
|
||
```bash
|
||
cd frontend
|
||
|
||
# 安装依赖
|
||
npm install
|
||
|
||
# 构建
|
||
npm run build
|
||
```
|
||
|
||
构建产物在 `frontend/dist/` 目录中。
|
||
|
||
### 5.4 上传静态文件到服务器
|
||
|
||
将本地构建产物上传到服务器:
|
||
|
||
```bash
|
||
# 在本地执行
|
||
scp -r frontend/dist/* user@你的服务器IP:/var/www/goal-planner/
|
||
```
|
||
|
||
或在服务器上从项目目录复制(如果已上传整个项目):
|
||
|
||
```bash
|
||
sudo mkdir -p /var/www/goal-planner
|
||
sudo cp -r /home/wwwroot/goal-planner/frontend/dist/* /var/www/goal-planner/
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 配置 Nginx
|
||
|
||
创建 Nginx 配置文件:
|
||
|
||
```bash
|
||
sudo vi /etc/nginx/conf.d/goal-planner.conf
|
||
```
|
||
|
||
### 方式一:Nginx 反向代理(推荐)
|
||
|
||
前后端统一通过 Nginx 访问,后端不对外暴露端口:
|
||
|
||
```nginx
|
||
server {
|
||
listen 80;
|
||
server_name 你的域名或IP;
|
||
|
||
# 前端静态文件
|
||
root /var/www/goal-planner;
|
||
index index.html;
|
||
|
||
# 前端路由 - SPA 应用所有路径都返回 index.html
|
||
location / {
|
||
try_files $uri $uri/ /index.html;
|
||
}
|
||
|
||
# 后端 API 反向代理
|
||
location /api-proxy/ {
|
||
rewrite ^/api-proxy/(.*) /$1 break;
|
||
proxy_pass http://127.0.0.1:8000;
|
||
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;
|
||
|
||
# SSE 支持 - 关键配置
|
||
proxy_buffering off;
|
||
proxy_cache off;
|
||
proxy_read_timeout 300s;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Connection '';
|
||
}
|
||
|
||
# 静态资源缓存
|
||
location /assets/ {
|
||
expires 30d;
|
||
add_header Cache-Control "public, immutable";
|
||
}
|
||
|
||
# 禁止访问隐藏文件
|
||
location ~ /\. {
|
||
deny all;
|
||
}
|
||
}
|
||
```
|
||
|
||
> **SSE 关键配置说明**:
|
||
> - `proxy_buffering off` — 禁用缓冲,确保 SSE 事件实时推送到客户端
|
||
> - `proxy_cache off` — 禁用缓存
|
||
> - `proxy_read_timeout 300s` — AI 生成可能耗时较长,增大超时时间
|
||
> - `proxy_http_version 1.1` + `Connection ''` — 保持长连接
|
||
|
||
### 方式二:前后端分离部署
|
||
|
||
后端直接监听 8000 端口对外服务:
|
||
|
||
```nginx
|
||
server {
|
||
listen 80;
|
||
server_name 你的域名或IP;
|
||
|
||
root /var/www/goal-planner;
|
||
index index.html;
|
||
|
||
location / {
|
||
try_files $uri $uri/ /index.html;
|
||
}
|
||
|
||
location /assets/ {
|
||
expires 30d;
|
||
add_header Cache-Control "public, immutable";
|
||
}
|
||
}
|
||
```
|
||
|
||
此方式下 `apiService.ts` 中的 `API_BASE_URL` 应设为 `http://你的域名或IP:8000`。
|
||
|
||
### 验证并重启 Nginx
|
||
|
||
```bash
|
||
sudo nginx -t
|
||
sudo systemctl restart nginx
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 使用 systemd 管理后端进程
|
||
|
||
创建 systemd 服务文件,实现开机自启和进程管理:
|
||
|
||
```bash
|
||
sudo vi /etc/systemd/system/goal-planner.service
|
||
```
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=Goal Planner Backend API
|
||
After=network.target mysql.service
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=root
|
||
WorkingDirectory=/home/wwwroot/goal-planner/backend
|
||
ExecStart=/home/wwwroot/goal-planner/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000
|
||
Restart=always
|
||
RestartSec=5
|
||
Environment=PYTHONUNBUFFERED=1
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
> 如果使用方式二(前后端分离),将 `--host 127.0.0.1` 改为 `--host 0.0.0.0` 以允许外部访问。
|
||
|
||
启动并设置开机自启:
|
||
|
||
```bash
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl start goal-planner
|
||
sudo systemctl enable goal-planner
|
||
```
|
||
|
||
常用管理命令:
|
||
|
||
```bash
|
||
sudo systemctl status goal-planner # 查看状态
|
||
sudo systemctl restart goal-planner # 重启
|
||
sudo systemctl stop goal-planner # 停止
|
||
sudo journalctl -u goal-planner -f # 查看实时日志
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 验证部署
|
||
|
||
```bash
|
||
# 检查后端健康状态
|
||
curl http://127.0.0.1:8000/api/health
|
||
# 预期返回: {"status":"ok"}
|
||
|
||
# 检查 Nginx 代理(方式一)
|
||
curl http://你的域名或IP/api-proxy/api/health
|
||
# 预期返回: {"status":"ok"}
|
||
|
||
# 浏览器访问
|
||
# http://你的域名或IP
|
||
```
|
||
|
||
---
|
||
|
||
## 9. HTTPS 配置(可选但推荐)
|
||
|
||
使用 Let's Encrypt 免费证书:
|
||
|
||
```bash
|
||
sudo apt install certbot python3-certbot-nginx # Ubuntu
|
||
sudo yum install certbot python3-certbot-nginx # CentOS
|
||
|
||
sudo certbot --nginx -d 你的域名
|
||
```
|
||
|
||
Certbot 会自动修改 Nginx 配置并配置 SSL 证书自动续期。
|
||
|
||
---
|
||
|
||
## 10. 更新部署
|
||
|
||
当代码更新后,执行以下步骤:
|
||
|
||
### 后端更新
|
||
|
||
```bash
|
||
# 服务器上拉取最新代码
|
||
cd /home/wwwroot/goal-planner
|
||
git pull
|
||
|
||
# 更新后端依赖(如有变动)
|
||
source /home/wwwroot/goal-planner/.venv/bin/activate
|
||
uv pip install -r backend/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple --only-binary :all:
|
||
|
||
# 重启后端
|
||
sudo systemctl restart goal-planner
|
||
```
|
||
|
||
### 前端更新
|
||
|
||
```bash
|
||
# 本地构建
|
||
cd frontend
|
||
npm install
|
||
npm run build
|
||
|
||
# 上传到服务器
|
||
scp -r dist/* user@你的服务器IP:/var/www/goal-planner/
|
||
```
|
||
|
||
---
|
||
|
||
## 文件结构总览
|
||
|
||
```
|
||
/home/wwwroot/goal-planner/
|
||
├── .venv/ # uv 创建的 Python 虚拟环境(项目根目录)
|
||
├── backend/
|
||
│ ├── .env # 环境变量配置(含数据库密码、API密钥)
|
||
│ ├── .env.example # 环境变量模板
|
||
│ ├── main.py # FastAPI 入口
|
||
│ ├── config.py # 配置读取
|
||
│ ├── database.py # 数据库连接
|
||
│ ├── requirements.txt # Python 依赖
|
||
│ ├── models/ # 数据模型
|
||
│ └── routes/ # API 路由
|
||
│ ├── auth.py
|
||
│ ├── generate.py
|
||
│ └── plans.py
|
||
└── frontend/
|
||
├── dist/ # 构建产物 → 部署到 /var/www/goal-planner/
|
||
├── services/
|
||
│ └── apiService.ts # API 地址配置(需修改 API_BASE_URL)
|
||
├── package.json
|
||
└── vite.config.ts
|
||
|
||
/var/www/goal-planner/ # Nginx 静态文件目录
|
||
/etc/nginx/conf.d/goal-planner.conf # Nginx 配置
|
||
/etc/systemd/system/goal-planner.service # 后端服务配置
|
||
```
|