# 生产环境部署文档 ## 概览 | 项目 | 内容 | |------|------| | 域名 | `https://trade.yuzhiran.com` | | 备案号 | 京ICP备2026007249号-1 | | 公安备案 | 京公网安备11011502039545号 | | 服务器 | 阿里云(Alibaba Cloud Linux 3) | | Web 服务器 | Nginx(宝塔面板管理) | | 后端 | FastAPI + uvicorn(Python 3.11, 2 workers) | | 前端 | uni-app Vue 3(H5 构建产物) | | 数据库 | 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 用户和授权 ```bash # 数据库 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. 部署代码到站点目录 ```bash # 将 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. 配置后端环境变量 ```bash cp deploy/backend/.env.production backend/.env # 编辑 backend/.env 填入: # - SECRET_KEY(随机字符串, 用 python3 -c "import secrets; print(secrets.token_urlsafe(48))" 生成) # - AI API Key(OPENAI_API_KEY / SENSENOVA_API_KEY 等) ``` ### 4. 安装 Python 3.11 和依赖 ```bash 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(重要!) ```bash # 编辑 backend/alembic/env.py,在第15行后加入: from app.config import settings config.set_main_option("sqlalchemy.url", settings.DATABASE_URL) # 这样 alembic 会从 .env 读取 DATABASE_URL,而非硬编码 ``` ### 6. 运行数据库迁移 ```bash 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. 构建前端 ```bash 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. 启动后端 ```bash # 设置权限 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 www` 或 `runuser`。 ### 10. 申请 SSL 证书(宝塔面板操作) 1. 宝塔面板 → 网站 → trade.yuzhiran.com → SSL 2. 选择 Let's Encrypt → 文件验证 3. 申请成功后自动配置 HTTPS 重定向 ### 11. 验证 ```bash 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 配置必须保留: ```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`: ```bash chown -R www:www /www/wwwroot/trade.yuzhiran.com/ ``` `www` 用户特点: - shell 为 `/sbin/nologin`,不能交互登录 - 启动后台进程需要 `sudo -u www` 或 `runuser` - 文件权限必须正确,否则 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 ``` ### Alembic(backend/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`。