Files

8.8 KiB
Raw Permalink Blame History

生产环境部署文档

概览

项目 内容
域名 https://trade.yuzhiran.com
备案号 京ICP备2026007249号-1
公安备案 京公网安备11011502039545号
服务器 阿里云(Alibaba Cloud Linux 3
Web 服务器 Nginx(宝塔面板管理)
后端 FastAPI + uvicornPython 3.11, 2 workers
前端 uni-app Vue 3H5 构建产物)
数据库 PostgreSQL 13, 数据库 foreign_trade
用户 www(宝塔默认用户)

目录结构

/www/wwwroot/trade.yuzhiran.com/
├── backend/                  # FastAPI 后端
│   ├── .env                  # 生产环境变量
│   ├── venv/                 # Python 3.11 虚拟环境
│   ├── app/                  # 应用代码
│   ├── alembic/              # 数据库迁移
│   ├── alembic.ini           # Alembic 配置(已改为从 .env 读取 URL
│   └── requirements.txt
├── uni-app/                  # 前端源码(保留用)
│   ├── src/
│   └── dist/build/h5/        # H5 构建产物
├── deploy/                   # 部署配置模板
│   ├── README.md
│   ├── backend/
│   │   ├── .env.production
│   │   └── supervisord.conf
│   ├── frontend/
│   │   └── nginx.conf
│   └── database/
│       └── migrate.sh
├── assets/                   # 前端静态资源
├── static/                   # 前端静态资源
└── index.html                # SPA 入口

# 日志
/www/wwwlogs/
├── trademate-backend.log     # uvicorn 后端日志
├── trademate-backend.error.log
└── trade.yuzhiran.com.log    # Nginx 访问日志

部署步骤

1. 创建 PostgreSQL 用户和授权

# 数据库 foreign_trade 已存在,需创建用户并授权
PGPASSWORD=your_password psql -U postgres -h localhost -c "CREATE ROLE foreign_trade WITH LOGIN PASSWORD 'your_password';"
PGPASSWORD=your_password psql -U postgres -h localhost -c "GRANT ALL PRIVILEGES ON DATABASE foreign_trade TO foreign_trade;"
PGPASSWORD=your_password psql -U postgres -h localhost -d foreign_trade -c "GRANT ALL ON SCHEMA public TO foreign_trade;"
PGPASSWORD=your_password psql -U postgres -h localhost -d foreign_trade -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO foreign_trade;"
PGPASSWORD=your_password psql -U postgres -h localhost -d foreign_trade -c "ALTER SCHEMA public OWNER TO foreign_trade;"

2. 部署代码到站点目录

# 将 production 分支代码复制到站点目录
cd /root/hermes-workspace/projects/trade-assistant
tar --exclude='.git' --exclude='node_modules' --exclude='__pycache__' \
    --exclude='*.pyc' --exclude='.pytest_cache' --exclude='venv' \
    --exclude='.coverage' --exclude='.env' \
    -cf - . | tar -xf - -C /www/wwwroot/trade.yuzhiran.com/

3. 配置后端环境变量

cp deploy/backend/.env.production backend/.env
# 编辑 backend/.env 填入:
#   - SECRET_KEY(随机字符串, 用 python3 -c "import secrets; print(secrets.token_urlsafe(48))" 生成)
#   - AI API KeyOPENAI_API_KEY / SENSENOVA_API_KEY 等)

4. 安装 Python 3.11 和依赖

yum install -y python3.11
cd /www/wwwroot/trade.yuzhiran.com/backend
python3.11 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install python-dotenv 'pydantic[dotenv]'

5. 配置 Alembic(重要!)

# 编辑 backend/alembic/env.py,在第15行后加入:
from app.config import settings
config.set_main_option("sqlalchemy.url", settings.DATABASE_URL)

# 这样 alembic 会从 .env 读取 DATABASE_URL,而非硬编码

6. 运行数据库迁移

cd /www/wwwroot/trade.yuzhiran.com/backend
source venv/bin/activate
alembic upgrade head

预期输出:

Running upgrade  -> 001, initial schema
Running upgrade 001 -> 002, add teams and analytics tables
Running upgrade 002 -> 003, add notifications, feedback, subscription, and p3 tables
Running upgrade 003 -> 004, add devices table for push notification registration
Running upgrade 004 -> 005, add followup_strategies and followup_logs tables

7. 构建前端

cd /www/wwwroot/trade.yuzhiran.com/uni-app
npm install
npm run build:h5
# 复制构建产物到站点根目录
cp -r dist/build/h5/* /www/wwwroot/trade.yuzhiran.com/

8. 配置 Nginx(宝塔面板操作)

在宝塔面板 → 网站 → 设置 → 配置文件 中替换为以下配置,或直接修改文件 /www/server/panel/vhost/nginx/trade.yuzhiran.com.conf

核心要点:

  • 保留 CERT-APPLY-CHECK 和 .well-known 配置(宝塔 SSL 证书验证需要)
  • 保留敏感文件/目录防护(宝塔自动生成)
  • 添加 location /api/ 代理到 127.0.0.1:8000
  • 添加 location / 的 SPA fallback: try_files $uri $uri/ /index.html
  • 删除 enable-php-00.conf 引用(本项目无需 PHP

Nginx 完整配置见 deploy/frontend/nginx.conf

9. 启动后端

# 设置权限
chown -R www:www /www/wwwroot/trade.yuzhiran.com/backend

# 切换 www 用户启动
sudo -u www nohup /www/wwwroot/trade.yuzhiran.com/backend/venv/bin/uvicorn \
    app.main:app --host 127.0.0.1 --port 8000 --workers 2 \
    >> /www/wwwlogs/trademate-backend.log 2>&1 &

注意: www 用户默认 shell 为 /sbin/nologin,无法通过 su - www 登录。必须使用 sudo -u wwwrunuser

10. 申请 SSL 证书(宝塔面板操作)

  1. 宝塔面板 → 网站 → trade.yuzhiran.com → SSL
  2. 选择 Let's Encrypt → 文件验证
  3. 申请成功后自动配置 HTTPS 重定向

11. 验证

curl -s http://127.0.0.1:8000/health                    # -> {"status":"ok"}
curl -s -H "Host: trade.yuzhiran.com" http://127.0.0.1/  # -> HTML 页面
curl -s https://trade.yuzhiran.com/api/v1/admin/health   # -> admin 健康检查

宝塔面板兼容说明

文件验证与 SSL

宝塔申请 SSL 证书时使用文件验证方式,会在 .well-known 目录放置验证文件。Nginx 配置必须保留:

#CERT-APPLY-CHECK--START
include /www/server/panel/vhost/nginx/well-known/trade.yuzhiran.com.conf;
#CERT-APPLY-CHECK--END

location ~ \.well-known {
    allow all;
}

这两个配置块缺一不可,否则宝塔面板会报 "配置文件被修改不支持文件验证"。

www 用户部署

宝塔面板以 www 用户运行,所有站点文件必须属于 www:www

chown -R www:www /www/wwwroot/trade.yuzhiran.com/

www 用户特点:

  • shell 为 /sbin/nologin,不能交互登录
  • 启动后台进程需要 sudo -u wwwrunuser
  • 文件权限必须正确,否则 Nginx 无法读取静态文件

宝塔面板可操作内容

操作 面板操作 说明
SSL 证书申请 文件验证,配置保留即可
Nginx 配置修改 可通过面板修改,注意保留 API 代理和 SPA fallback
数据库管理 phpMyAdmin / 面板 phpPgAdmin
文件管理 可查看/编辑站点文件
进程管理 后端 uvicorn 需命令行管理,面板 Python 项目管理器暂未配置

推荐的生产维护方式

# 重启后端
kill -9 $(pgrep -f "uvicorn app.main" | head -1)
sudo -u www nohup /www/wwwroot/trade.yuzhiran.com/backend/venv/bin/uvicorn \
    app.main:app --host 127.0.0.1 --port 8000 --workers 2 \
    >> /www/wwwlogs/trademate-backend.log 2>&1 &

# 查看后端日志
tail -f /www/wwwlogs/trademate-backend.log

# 重新构建前端
cd /www/wwwroot/trade.yuzhiran.com/uni-app && npm run build:h5
cp -r dist/build/h5/* /www/wwwroot/trade.yuzhiran.com/

# 数据库迁移
cd /www/wwwroot/trade.yuzhiran.com/backend && source venv/bin/activate && alembic upgrade head

关键配置

环境变量(backend/.env

DATABASE_URL=postgresql+asyncpg://foreign_trade:password@localhost:5432/foreign_trade
FRONTEND_URL=https://trade.yuzhiran.com
BACKEND_URL=https://trade.yuzhiran.com
DEBUG=false
DB_ECHO=false

Alembicbackend/alembic.ini

生产环境不再硬编码数据库 URL,改为从 .env 读取。alembic/env.py 中通过 config.set_main_option("sqlalchemy.url", settings.DATABASE_URL) 动态设置。

常见问题

Q: 前端页面空白 / 路由 404

重新加载页面(SPA fallback),确认 Nginx 配置有 try_files $uri $uri/ /index.html

Q: API 请求 500,日志显示 "invalid UUID"

路由顺序问题 —— 参数化路由(如 /{customer_id})必须在具名路由(如 /health-scores)之后定义。参照 customer.py 的修正。

Q: 宝塔面板申请 SSL 失败

检查 Nginx 配置中是否保留了 #CERT-APPLY-CHECK 注释块和 .well-known location。

Q: 后端启动后马上退出

检查端口 8000 是否被占用:lsof -i :8000。检查日志:tail -f /www/wwwlogs/trademate-backend.log