Files
shanxia2.0/生产环境部署/README.md
T
2026-09-28 10:47:42 +08:00

356 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# shanxia2.0 生产环境部署方案
> 目标机器:`121.43.228.102`
> 与现有 CRM(80 端口 / `web.conf`)**并存**,通过 **9911(前端)+ 9111(后端)** 独立端口部署山峡一体化门户。
---
## 1. 部署思路总览
### 1.1 架构
```
┌─────────────────────────────────────────┐
│ 121.43.228.102 │
│ │
浏览器 ──────────►│ nginx :9911 │
(管理端) │ ├─ / → 静态 dist (SPA) │
│ └─ /api/* → 127.0.0.1:9111 │
│ │
│ uvicorn :9111 (FastAPI) │
│ ├─ MySQL 47.99.164.66:3306 │
│ ├─ Redis 47.99.164.66:16379 │
│ └─ MinIO 47.99.164.66:20004 │
│ │
浏览器 ──────────►│ nginx :80 (现有 CRM,保持不变) │
(CRM) │ └─ /prod-api/* → :8080 │
└─────────────────────────────────────────┘
```
### 1.2 核心原则
| 项 | 说明 |
|---|---|
| **端口隔离** | CRM 继续占用 80;shanxia2.0 使用 9911/9111,互不影响 |
| **同库同中间件** | 数据库、Redis、MinIO 与本地开发一致(远程 `47.99.164.66`) |
| **Nginx 反代 API** | 前端 `VITE_API_URL=/api`,由 Nginx 转发到后端,避免浏览器跨域 |
| **后端仅本机监听** | 9111 建议只绑定 `127.0.0.1`,对外只暴露 9911 |
| **环境文件分离** | 生产使用 `backend/.env.production`,不直接使用开发 `.env` |
| **构建在本地/CI** | 服务器只放 `dist` 与 Python 源码,不在生产机跑 `pnpm dev` |
### 1.3 目录约定(生产机)
| 路径 | 内容 |
|---|---|
| `/iflytek/shanxia2.0/backend` | Python 后端源码 + venv + `.env.production` |
| `/iflytek/shanxia2.0/web/dist` | 前端 `pnpm build` 产物(仓库对应 `web-admin/dist`) |
| `/etc/nginx/conf.d/shanxia2.0.conf` | Nginx 站点配置(见同目录模板) |
> 仓库前端工程名为 `web-admin`,部署到服务器时目录按约定命名为 `web/dist`。
---
## 2. 前置条件
### 2.1 服务器软件
- **Python 3.9+**(与本地 venv 一致;需 `python3-venv`)
- **Nginx**(已有,用于 CRM)
- **Node.js 20.19+ / pnpm 8.8+**(仅在构建机构建,生产机可选)
### 2.2 网络与防火墙
- 安全组/防火墙放行 **9911/TCP**(对外 Web 访问)
- **9111** 建议不对公网开放(仅 Nginx 本机反代)
- 确认生产机可访问 `47.99.164.66:3306 / 16379 / 20004`
### 2.3 数据库
- 库名:`shanxia2.0`(与本地 `DATABASE_URL` 一致)
- 基线 DDL:`docs/sql/shanxia2.0.sql`
- 增量脚本:按日期顺序执行 `docs/sql/2026*.sql` 等迁移文件
- 可选表:`docs/sql/optional-sys-api-request-log.sql`(不建表则设置 `API_REQUEST_LOG_ENABLED=false`)
---
## 3. 部署步骤
### 阶段 A:准备代码(本地或 CI)
#### A1. 检出/打包后端
```bash
# 本地打包示例(排除 venv、日志、缓存)
cd /path/to/shanxia2.0
tar czf shanxia2.0-backend.tar.gz \
--exclude='backend/venv' \
--exclude='backend/logs' \
--exclude='backend/__pycache__' \
--exclude='backend/.env' \
backend/
```
#### A2. 配置生产环境变量
1. 复制 `生产环境部署/backend.env.production.example` → 服务器 `backend/.env.production`
2. 以本地 `backend/.env` 中的 **DATABASE / Redis / MinIO** 值为基准填入
3. **必须修改**的生产项:
- `DEBUG=false`
- `SECRET_KEY` → 随机长字符串(勿用默认值)
- `LOGIN_RSA_PRIVATE_KEY_PEM` → 固定 PEM(多 worker / 重启后登录公钥不变)
- `BACKEND_CORS_ORIGINS=["http://121.43.228.102:9911"]`(若后续绑域名一并加入)
- `PUBLIC_WEB_ORIGIN=http://121.43.228.102:9911`(公开 H5 页链接)
#### A3. 构建前端
1. 复制 `生产环境部署/web-admin.env.production.example` → `web-admin/.env.production`
2. 构建:
```bash
cd web-admin
pnpm install
pnpm build
# 产物:web-admin/dist/
```
3. 打包 dist:
```bash
tar czf shanxia2.0-web-dist.tar.gz -C web-admin dist
```
---
### 阶段 B:上传到生产机
```bash
# 在本地执行(示例)
scp shanxia2.0-backend.tar.gz root@121.43.228.102:/iflytek/shanxia2.0/
scp shanxia2.0-web-dist.tar.gz root@121.43.228.102:/iflytek/shanxia2.0/
scp 生产环境部署/nginx-shanxia2.0.conf root@121.43.228.102:/etc/nginx/conf.d/
```
在服务器解压:
```bash
mkdir -p /iflytek/shanxia2.0/backend /iflytek/shanxia2.0/web
cd /iflytek/shanxia2.0
tar xzf shanxia2.0-backend.tar.gz
mkdir -p web && tar xzf shanxia2.0-web-dist.tar.gz -C web
# 解压后路径应为 /iflytek/shanxia2.0/web/dist/index.html
```
---
### 阶段 C:后端初始化与启动
```bash
cd /iflytek/shanxia2.0/backend
# 创建虚拟环境并安装依赖
python3 -m venv venv
./venv/bin/pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
# 确认环境文件
ls -la .env.production
# 启动(端口 9111,2 worker)
PORT=9111 WORKERS=2 ENV_FILE=./.env.production ./start-prod.sh start
# 查看状态与日志
./start-prod.sh status
./start-prod.sh logs
```
健康检查(服务器本机):
```bash
curl -s http://127.0.0.1:9111/health
# 期望:{"status":"healthy"}
```
---
### 阶段 D:Nginx 配置
1. 使用本目录 `nginx-shanxia2.0.conf`(已按 9911 / 9111 写好)
2. 检查并重载:
```bash
nginx -t
nginx -s reload
# 或 systemctl reload nginx
```
3. 验证:
```bash
curl -s http://127.0.0.1:9911/health
curl -s http://127.0.0.1:9911/api/... # 任选一个公开接口
curl -I http://127.0.0.1:9911/
```
---
### 阶段 E:业务验收
| 检查项 | 操作 | 期望 |
|---|---|---|
| 静态页 | 浏览器打开 `http://121.43.228.102:9911` | 登录页正常 |
| 登录 | admin / 111111(或实际账号) | RSA 登录成功,进入工作台 |
| API 代理 | F12 Network 看请求 | 均为同源 `/api/...`,无 CORS 报错 |
| 附件 | 上传/预览 | MinIO URL 可访问 |
| 路由 | 刷新任意 `#/pl/...` 页面 | 不出现 404(SPA fallback) |
| CRM 不受影响 | 访问 `http://121.43.228.102` | CRM 仍正常 |
---
## 4. 与 CRM Nginx 配置的对比
| 对比项 | CRM (`web.conf`) | shanxia2.0 (`shanxia2.0.conf`) |
|---|---|---|
| 监听端口 | 80 | **9911** |
| 静态根目录 | `/iflytek/prod/dist` | `/iflytek/shanxia2.0/web/dist` |
| API 前缀 | `/prod-api/` | **`/api/`** |
| 后端端口 | 8080 (Java) | **9111** (Python) |
| SSE | 有专用 location | 当前门户暂无 SSE,可后续按需追加 |
shanxia2.0 的 Nginx 写法**参照 CRM 的代理头、超时、Gzip、SPA fallback**,仅替换端口与路径前缀。
---
## 5. 环境变量要点
### 5.1 后端(`.env.production`)
详见 `backend.env.production.example`。与本地 `.env` 对齐的字段:
- `DATABASE_URL`
- `REDIS_*`
- `MINIO_*` / `STORAGE_TYPE=minio`
- `DEFAULT_TENANT_NO=shanxia2.0`
- `API_ENCRYPT_*`(当前本地为 `false`,生产保持一致即可;若开启需前后端同时开启且密钥一致)
生产**额外**注意:
- `DEBUG=false`
- `LOGIN_ALLOW_PLAINTEXT_LOGIN=false`
- 配置固定 `LOGIN_RSA_PRIVATE_KEY_PEM`(可从本地生成后复制,或使用 `openssl genrsa 2048`)
### 5.2 前端(`.env.production`,构建时生效)
详见 `web-admin.env.production.example`:
- `VITE_API_URL=/api`(走 Nginx 同源代理)
- `VITE_BASE_URL=/`
- `VITE_API_ENCRYPT_ENABLED=false`(与后端一致)
- `VITE_MINIO_BASE_URL=https://res.shanxiachem.com/ruoyi`(与后端 `MINIO_BASE_URL` 一致)
---
## 6. 日常运维
### 6.0 一键发版(推荐)
macOS 本机从仓库根目录执行(凭据读自根目录 `生产机器账号密码`,密码不写进脚本):
```bash
./生产环境部署/deploy-release.sh
# 已有 dist 时可跳过构建:
./生产环境部署/deploy-release.sh --skip-build
```
顺序:本地 `pnpm build` → 备份远程 `web` → 同步 `dist`(**保留**远程 `dist/src`)→ 备份远程 `backend` → 替换 `backend/app` → `PORT=9111 WORKERS=1 ENV_FILE=./.env.production ./start-prod.sh restart` → 健康检查。
备份落在 `/iflytek/shanxia2.0/bak/web-*` 与 `backend-*`。依赖:`ssh`、`rsync`、`sshpass`(`brew install hudochenkov/sshpass/sshpass`)、`pnpm`。
### 6.1 更新后端(手工)
```bash
cd /iflytek/shanxia2.0/backend
# 上传新代码后
./venv/bin/pip install -r requirements.txt
PORT=9111 WORKERS=1 ENV_FILE=./.env.production ./start-prod.sh restart
```
### 6.2 更新前端(手工)
```bash
# 本地 build 后上传 dist;务必保留远程 dist/src
rsync -avz --delete --exclude 'src/' web-admin/dist/ root@121.43.228.102:/iflytek/shanxia2.0/web/dist/
# 无需重启后端;浏览器强刷或清缓存
```
### 6.3 数据库变更
1. 在 `docs/sql/` 编写增量 SQL
2. 在生产库按顺序执行
3. 再发版后端/前端
### 6.4 日志位置
| 组件 | 路径 |
|---|---|
| 后端 | `/iflytek/shanxia2.0/backend/logs/backend-prod.log` |
| Nginx | 按现有 CRM 同样 log 目录配置(可在 conf 中取消注释) |
### 6.5 开机自启(可选)
可使用 systemd unit 管理 `start-prod.sh`:
```ini
# /etc/systemd/system/shanxia2.0-backend.service
[Unit]
Description=shanxia2.0 FastAPI Backend
After=network.target
[Service]
Type=forking
WorkingDirectory=/iflytek/shanxia2.0/backend
Environment=PORT=9111
Environment=WORKERS=2
Environment=ENV_FILE=/iflytek/shanxia2.0/backend/.env.production
ExecStart=/iflytek/shanxia2.0/backend/start-prod.sh start
ExecStop=/iflytek/shanxia2.0/backend/start-prod.sh stop
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
```bash
systemctl daemon-reload
systemctl enable shanxia2.0-backend
systemctl start shanxia2.0-backend
```
---
## 7. 回滚策略
1. **前端**:`/iflytek/shanxia2.0/bak/web-*` 中对应备份覆盖回 `web`(注意勿误删业务依赖的 `dist/src`)
2. **后端**:从 `bak/backend-*` 还原后,在 `backend` 目录执行 `PORT=9111 WORKERS=1 ENV_FILE=./.env.production ./start-prod.sh restart`
3. **数据库**:增量 SQL 应可逆或先备份;重大变更前 `mysqldump`
---
## 8. 后续可选增强
- **域名 + HTTPS**:为 9911 配置 `portal.shanxiachem.com` + SSL,并更新 `BACKEND_CORS_ORIGINS`
- **API 加密**:生产开启 `API_ENCRYPT_ENABLED=true`,前后端密钥与排除路径保持一致
- **独立 API 域名**:小程序/外部系统可配置 `http://121.43.228.102:9911/api` 或单独域名
- **监控**:对 `/health` 做存活探测;对接现有 Spring Boot Admin 以外的监控
---
## 9. 文件清单
| 文件 | 用途 |
|---|---|
| `README.md` | 本文档 |
| `deploy-release.sh` | macOS 一键发版(前端→后端,含备份与健康检查) |
| `nginx-shanxia2.0.conf` | Nginx 站点模板 |
| `backend.env.production.example` | 后端生产环境变量模板 |
| `web-admin.env.production.example` | 前端构建环境变量模板 |
| `deploy-checklist.md` | 上线检查清单(可打印) |