diff --git a/deploy/README.md b/deploy/README.md index a4119e5..7a1fe9f 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,105 +1,28 @@ -# 生产部署文档(宝塔面板) +# 部署文档 -## 前提条件 +## 生产环境文档 -宝塔面板已安装: -- Nginx -- PostgreSQL(已有数据库 `foreign_trade`) -- Redis -- Python 3.11+ +生产环境的详细部署步骤、配置说明和宝塔面板兼容指南请参阅: -## 目录结构(宝塔站点根目录) +👉 **`docs/PRODUCTION.md`** -``` -/www/wwwroot/trade.yuzhiran.com/ -├── backend/ # FastAPI 后端代码 -│ ├── .env # 生产环境变量 -│ ├── app/ -│ ├── alembic/ -│ └── ... -├── frontend/ # 前端静态文件 -│ └── dist/ # uni-app 构建产物 -└── deploy/ # 部署配置(此目录) -``` +该文档包含: +- 完整的部署步骤(从建库到验证) +- 宝塔面板兼容说明(SSL 证书申请、www 用户部署) +- 常见问题排查 +- 生产维护命令速查 -## 部署步骤 +## 配置文件模板 -### 1. 上传代码到服务器 +本目录下的文件为部署模板,实际部署时需根据环境调整: -将项目代码(production 分支)上传到 `/www/wwwroot/trade.yuzhiran.com/` +| 文件 | 用途 | +|------|------| +| `backend/.env.production` | 生产环境变量模板,复制为 `backend/.env` 后编辑 | +| `backend/supervisord.conf` | Supervisor 进程守护配置(备选) | +| `frontend/nginx.conf` | Nginx 配置参考(宝塔面板亦可使用) | +| `database/migrate.sh` | 数据库迁移脚本 | -### 2. 配置后端环境变量 +## 相关文件 -```bash -cp deploy/backend/.env.production backend/.env -# 编辑 backend/.env,填入: -# - SECRET_KEY(随机字符串,用于 JWT 签名) -# - AI API Key(OPENAI_API_KEY 或 SENSENOVA_API_KEY 等) -vim backend/.env -``` - -### 3. 安装后端依赖 & 运行迁移 - -```bash -cd backend -python3 -m venv venv -source venv/bin/activate -pip install -r requirements.txt -alembic upgrade head -``` - -### 4. 构建前端 - -```bash -cd uni-app -npm install -npm run build:h5 -# 产物在 dist/build/h5/ 目录 -# 将 dist/build/h5/ 下的内容复制到 /www/wwwroot/trade.yuzhiran.com/frontend/dist/ -``` - -### 5. 配置 Nginx(宝塔面板操作) - -在宝塔面板中: -1. 添加站点 `trade.yuzhiran.com` -2. 站点根目录设为 `/www/wwwroot/trade.yuzhiran.com/frontend/dist` -3. 修改 Nginx 配置,参考 `deploy/frontend/nginx.conf` - -关键配置点: -- 根目录指向前端 dist -- `/api/` 反向代理到 `http://127.0.0.1:8000` -- SPA fallback: `try_files $uri $uri/ /index.html` - -### 6. 启动后端(宝塔 Python 项目管理器) - -在宝塔面板中使用 **Python项目管理器**: -- 项目路径:`/www/wwwroot/trade.yuzhiran.com/backend` -- Python 版本:3.11 -- 启动命令:`uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 2` -- 项目名称:`trademate-backend` - -或者使用 Supervisor 命令行部署: -```bash -pip install supervisor -supervisord -c deploy/backend/supervisord.conf -``` - -### 7. 验证 - -- 访问 https://trade.yuzhiran.com → 前端正常加载 -- 访问 https://trade.yuzhiran.com/api/health → 返回 `{"status": "ok"}` - -## 常见问题 - -**Q: 数据库迁移失败?** -A: 确认 PostgreSQL 中 `foreign_trade` 数据库已创建,用户有权限。 - ```sql - CREATE DATABASE foreign_trade; - GRANT ALL PRIVILEGES ON DATABASE foreign_trade TO foreign_trade; - ``` - -**Q: 前端 API 请求 502?** -A: 检查后端是否启动,以及 Nginx 中 `/api/` 的 proxy_pass 地址是否正确。 - -**Q: CORS 报错?** -A: 确认 `backend/.env` 中的 `FRONTEND_URL` 与实际前端域名一致。 +- `.env.example` — 开发环境变量示例(位于 `backend/`) diff --git a/docs/PRODUCTION.md b/docs/PRODUCTION.md new file mode 100644 index 0000000..2e35294 --- /dev/null +++ b/docs/PRODUCTION.md @@ -0,0 +1,262 @@ +# 生产环境部署文档 + +## 概览 + +| 项目 | 内容 | +|------|------| +| 域名 | `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`。