Files
goal-planner/DEPLOY.md
T
2026-11-02 15:45:49 +08:00

12 KiB
Raw Blame History

Goal Planner Linux 部署指南

环境要求

服务器

  • Linux 服务器(Ubuntu 20.04+ / CentOS 7+)
  • Python 3.11+(由 uv 管理,不依赖系统 Python)
  • MySQL 5.7+ / 8.0(需提前安装)
  • Nginx(需提前安装)
  • 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

curl -LsSf https://astral.sh/uv/install.sh | sh

安装完成后,需要让 uv 命令生效(二选一):

# 方式一:执行以下命令(推荐,立即生效)
source $HOME/.local/bin/env

# 方式二:重新连接 SSH

验证安装:

uv --version

2. 配置 MySQL

# 登录 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:

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 配置环境变量

cd /home/wwwroot/goal-planner/backend
cp .env.example .env

编辑 .env 文件:

vi .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 创建虚拟环境并安装依赖

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 验证后端启动

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(简单快速)

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 &

常用操作:

# 查看日志
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 中:

const API_BASE_URL = 'http://localhost:8000';

部署前必须修改为实际的后端地址。根据你的部署方式选择:

方式一:使用 Nginx 反向代理(推荐)

将 API 地址改为相对路径,由 Nginx 统一代理:

const API_BASE_URL = '/api-proxy';

这样前端请求 /api-proxy/api/generate/ 会被 Nginx 转发到后端 http://127.0.0.1:8000/api/generate/,无需暴露后端端口。

方式二:直接指向后端地址

如果你的后端运行在独立域名或端口上:

const API_BASE_URL = 'http://你的服务器IP:8000';

注意:此方式需要后端开放 8000 端口,并在 main.py 的 CORS 配置中添加前端域名。

5.2 修改后端 CORS 配置(方式一不需要)

如果使用方式二,需要修改 backend/main.py 中的 CORS 允许来源:

origins = [
    "http://你的域名",
    "http://你的服务器IP",
]

5.3 本地构建前端

在本地开发机器上执行构建(不需要在服务器上安装 Node.js):

cd frontend

# 安装依赖
npm install

# 构建
npm run build

构建产物在 frontend/dist/ 目录中。

5.4 上传静态文件到服务器

将本地构建产物上传到服务器:

# 在本地执行
scp -r frontend/dist/* user@你的服务器IP:/var/www/goal-planner/

或在服务器上从项目目录复制(如果已上传整个项目):

sudo mkdir -p /var/www/goal-planner
sudo cp -r /home/wwwroot/goal-planner/frontend/dist/* /var/www/goal-planner/

6. 配置 Nginx

创建 Nginx 配置文件:

sudo vi /etc/nginx/conf.d/goal-planner.conf

方式一: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 端口对外服务:

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

sudo nginx -t
sudo systemctl restart nginx

7. 使用 systemd 管理后端进程

创建 systemd 服务文件,实现开机自启和进程管理:

sudo vi /etc/systemd/system/goal-planner.service
[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 以允许外部访问。

启动并设置开机自启:

sudo systemctl daemon-reload
sudo systemctl start goal-planner
sudo systemctl enable goal-planner

常用管理命令:

sudo systemctl status goal-planner    # 查看状态
sudo systemctl restart goal-planner   # 重启
sudo systemctl stop goal-planner      # 停止
sudo journalctl -u goal-planner -f    # 查看实时日志

8. 验证部署

# 检查后端健康状态
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 免费证书:

sudo apt install certbot python3-certbot-nginx   # Ubuntu
sudo yum install certbot python3-certbot-nginx    # CentOS

sudo certbot --nginx -d 你的域名

Certbot 会自动修改 Nginx 配置并配置 SSL 证书自动续期。


10. 更新部署

当代码更新后,执行以下步骤:

后端更新

# 服务器上拉取最新代码
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

前端更新

# 本地构建
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  # 后端服务配置