docs: 明确前端本地打包部署流程,优化部署脚本

更新内容:
- DEPLOY_ONLINE_GUIDE.md: 详细说明前端本地打包的优势和流程
- deploy-1panel.sh: 优化部署脚本,添加前端构建验证
- 强调前后端分离部署的架构差异

核心变更:
1. 明确说明前端必须本地打包(npm run build)
2. 上传的是打包后的静态文件,不需要服务器 Node.js
3. 添加前端构建验证步骤
4. 优化部署流程提示和输出

部署流程:
- 本地:前端构建 → 验证构建 → 上传静态文件
- 服务器:后端代码 → Docker 容器运行
- 1Panel:Nginx 托管静态文件 + 反向代理后端 API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
root
2026-02-27 18:24:42 +08:00
parent 7bdd0850f5
commit 5f110b6988
2 changed files with 287 additions and 97 deletions
+97 -36
View File
@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# X-Server Mobile 1Panel 静态站点部署脚本 # uniservice-mobile.hnxinyouhe.com 部署脚本
# 使用方法: ./deploy-1panel.sh [server] # 使用方法: ./deploy-1panel.sh [server]
set -e set -e
@@ -22,6 +22,7 @@ REMOTE_BACKEND_DIR="/opt/x-server-mobile/backend"
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
log_info() { log_info() {
@@ -36,20 +37,30 @@ log_error() {
echo -e "${RED}[ERROR]${NC} $1" echo -e "${RED}[ERROR]${NC} $1"
} }
log_step() {
echo -e "${BLUE}==>${NC} $1"
}
# ============================================ # ============================================
# 检查环境 # 检查环境
# ============================================ # ============================================
check_env() { check_env() {
log_info "检查部署环境..." log_step "检查部署环境..."
if ! command -v rsync &> /dev/null; then if ! command -v rsync &> /dev/null; then
log_error "rsync 未安装,请先安装: apt-get install rsync" log_error "rsync 未安装,请先安装: apt-get install rsync"
log_info "macOS: brew install rsync"
exit 1 exit 1
fi fi
if [ ! -d "$FRONTEND_BUILD_DIR" ]; then if [ ! -d "$FRONTEND_BUILD_DIR" ]; then
log_error "前端构建目录不存在: $FRONTEND_BUILD_DIR" log_error "❌ 前端构建目录不存在: $FRONTEND_BUILD_DIR"
log_info "请先运行: cd frontend && npm install && npm run build" echo ""
log_info "请先在本地构建前端:"
echo " cd frontend"
echo " npm install"
echo " npm run build"
echo ""
exit 1 exit 1
fi fi
@@ -57,24 +68,37 @@ check_env() {
} }
# ============================================ # ============================================
# 构建前端 # 验证前端构建
# ============================================ # ============================================
build_frontend() { verify_frontend() {
log_info "构建前端..." log_step "验证前端构建..."
cd frontend
npm run build if [ ! -f "$FRONTEND_BUILD_DIR/index.html" ]; then
cd .. log_error "❌ 前端构建不完整,缺少 index.html"
log_info "✓ 前端构建完成" exit 1
fi
if [ ! -d "$FRONTEND_BUILD_DIR/assets" ]; then
log_warn "⚠️ 未找到 assets 目录,可能是构建失败"
fi
log_info "✓ 前端构建验证通过"
echo " - index.html: 存在"
echo " - 构建时间: $(ls -lt $FRONTEND_BUILD_DIR/index.html | head -1 | awk '{print $6, $7, $8}')"
} }
# ============================================ # ============================================
# 部署前端(上传静态文件) # 部署前端(上传静态文件)
# ============================================ # ============================================
deploy_frontend() { deploy_frontend() {
log_info "部署前端到 1Panel 静态站点..." log_step "部署前端静态文件..."
echo " 本地: $FRONTEND_BUILD_DIR/"
echo " 远程: ${DEPLOY_USER}@${SERVER}:${REMOTE_ROOT}/"
rsync -avz --delete \ rsync -avz --delete \
--exclude='*.map' \ --exclude='*.map' \
--progress \
${FRONTEND_BUILD_DIR}/ \ ${FRONTEND_BUILD_DIR}/ \
${DEPLOY_USER}@${SERVER}:${REMOTE_ROOT}/ ${DEPLOY_USER}@${SERVER}:${REMOTE_ROOT}/
@@ -85,15 +109,21 @@ deploy_frontend() {
# 部署后端 # 部署后端
# ============================================ # ============================================
deploy_backend() { deploy_backend() {
log_info "部署后端..." log_step "部署后端代码..."
# 创建后端目录(如果不存在) # 创建后端目录(如果不存在)
ssh ${DEPLOY_USER}@${SERVER} "mkdir -p ${REMOTE_BACKEND_DIR}" ssh ${DEPLOY_USER}@${SERVER} "mkdir -p ${REMOTE_BACKEND_DIR}"
echo " 本地: $BACKEND_SOURCE_DIR/"
echo " 远程: ${DEPLOY_USER}@${SERVER}:${REMOTE_BACKEND_DIR}/"
rsync -avz \ rsync -avz \
--exclude='vendor' \ --exclude='vendor' \
--exclude='runtime' \ --exclude='runtime' \
--exclude='.git' \ --exclude='.git' \
--exclude='node_modules' \
--exclude='.idea' \
--progress \
${BACKEND_SOURCE_DIR}/ \ ${BACKEND_SOURCE_DIR}/ \
${DEPLOY_USER}@${SERVER}:${REMOTE_BACKEND_DIR}/ ${DEPLOY_USER}@${SERVER}:${REMOTE_BACKEND_DIR}/
@@ -104,22 +134,54 @@ deploy_backend() {
# 重启后端容器 # 重启后端容器
# ============================================ # ============================================
restart_backend() { restart_backend() {
log_info "重启后端容器..." log_step "重启后端容器..."
ssh ${DEPLOY_USER}@${SERVER} << 'EOF' ssh ${DEPLOY_USER}@${SERVER} << 'EOF'
echo "正在检查后端目录..."
cd /opt/x-server-mobile cd /opt/x-server-mobile
# 停止旧容器 if [ ! -f "deploy/docker-compose.prod.yml" ]; then
docker-compose -f deploy/docker-compose.prod.yml down echo "❌ docker-compose.prod.yml 不存在"
echo " 请先上传部署配置文件"
exit 1
fi
# 启动新容器 echo "停止旧容器..."
docker-compose -f deploy/docker-compose.prod.yml down 2>/dev/null || true
echo "启动新容器..."
docker-compose -f deploy/docker-compose.prod.yml up -d docker-compose -f deploy/docker-compose.prod.yml up -d
# 查看容器状态 echo ""
echo "容器状态:"
docker ps | grep x-server docker ps | grep x-server
echo ""
echo "✓ 后端容器重启完成" echo "✓ 后端容器重启完成"
EOF EOF
if [ $? -eq 0 ]; then
log_info "✓ 后端容器重启成功"
else
log_error "✗ 后端容器重启失败"
exit 1
fi
}
# ============================================
# 显示部署信息
# ============================================
show_deployment_info() {
echo ""
log_step "部署信息"
echo ""
echo "🌐 访问地址: https://uniservice-mobile.hnxinyouhe.com"
echo ""
echo "📁 前端目录: ${REMOTE_ROOT}"
echo "📁 后端目录: ${REMOTE_BACKEND_DIR}"
echo ""
echo "📊 后端容器: x-server-backend-prod (端口 8787)"
echo ""
} }
# ============================================ # ============================================
@@ -127,43 +189,42 @@ EOF
# ============================================ # ============================================
main() { main() {
echo "==========================================" echo "=========================================="
echo " X-Server Mobile 1Panel 部署脚本" echo " uniservice-mobile 部署脚本"
echo "==========================================" echo "=========================================="
echo "" echo ""
echo "目标服务器: ${SERVER}" echo "📍 目标服务器: ${SERVER}"
echo "" echo ""
# 检查环境 # 检查环境
check_env check_env
# 询问是否构建前端 # 验证前端构建
read -p "是否需要构建前端? (y/N): " build_frontend_choice verify_frontend
if [[ $build_frontend_choice =~ ^[Yy]$ ]]; then
build_frontend echo ""
read -p "是否继续部署? (y/N): " confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
log_warn "部署已取消"
exit 0
fi fi
echo ""
# 部署前端 # 部署前端
deploy_frontend deploy_frontend
# 询问是否部署后端 echo ""
read -p "是否需要部署后端? (y/N): " deploy_backend_choice read -p "是否需要部署后端? (y/N): " deploy_backend_choice
if [[ $deploy_backend_choice =~ ^[Yy]$ ]]; then if [[ $deploy_backend_choice =~ ^[Yy]$ ]]; then
echo ""
deploy_backend deploy_backend
restart_backend restart_backend
else
log_info "跳过后端部署"
fi fi
echo "" echo ""
log_info "==========================================" show_deployment_info
log_info "部署完成!"
log_info "=========================================="
echo ""
echo "访问地址: https://uniservice-mobile.hnxinyouhe.com"
echo ""
echo "后续步骤:"
echo "1. 在 1Panel 面板中找到网站配置"
echo "2. 将 deploy/nginx-1panel.conf 的内容添加到 Nginx 配置中"
echo "3. 重载 Nginx 配置"
echo ""
} }
# 执行主流程 # 执行主流程
+190 -61
View File
@@ -13,19 +13,38 @@
--- ---
## 部署架构说明
**重要:前后端分离部署**
| 组件 | 部署位置 | 部署方式 |
|------|---------|---------|
| **前端** | 1Panel 静态站点 | 本地打包 → 上传静态文件 |
| **后端** | Docker 容器 | 上传代码 → 容器运行 |
### 为什么前端要本地打包?
1. **服务器不需要 Node.js** - 只需 Nginx 托管静态文件
2. **打包速度快** - 本地开发机性能通常更好
3. **节省服务器资源** - 不占用服务器 CPU/内存编译
4. **避免环境问题** - 本地打包更稳定可靠
---
## 部署目录结构 ## 部署目录结构
``` ```
线上服务器: 线上服务器:
/www/sites/uniservice-mobile.hnxinyouhe.com/ /www/sites/uniservice-mobile.hnxinyouhe.com/
├── index/ ← 前端静态文件 ├── index/ ← 前端静态文件(本地打包后上传)
│ ├── index.html │ ├── index.html
│ ├── assets/ │ ├── assets/
│ └── ... │ └── ...
├── log/ ← 访问日志 ├── log/ ← 访问日志
│ ├── access.log │ ├── access.log
│ └── error.log │ └── error.log
└── ssl/ ← SSL 证书 └── ssl/ ← SSL 证书(1Panel 管理)
├── fullchain.pem ├── fullchain.pem
└── privkey.pem └── privkey.pem
@@ -47,47 +66,61 @@
## 快速部署步骤 ## 快速部署步骤
### 方式一:使用部署脚本(推荐) ### 第一步:本地打包前端(开发机执行)
```bash ```bash
# 1. 构建前端 # 在开发机本地执行
cd /www/x-server-mobile/frontend cd /www/x-server-mobile/frontend
# 安装依赖(首次或依赖变化时)
npm install
# 构建生产版本
npm run build npm run build
# 2. 执行部署脚本 # 构建完成后,静态文件在 frontend/dist/ 目录
./deploy/deploy-1panel.sh your-server-ip ls frontend/dist/
# 输出: index.html, assets/, ...
# 脚本会提示:
# - 是否需要构建前端(已构建则选 N)
# - 是否需要部署后端
# - 自动重启后端容器
``` ```
### 方式二:手动部署 ### 第二步:上传到服务器
#### 1. 前端部署
```bash ```bash
# 本地构建 # 上传前端静态文件到服务器
cd /www/x-server-mobile/frontend
npm run build
# 上传静态文件到服务器
rsync -avz --delete frontend/dist/* root@your-server:/www/sites/uniservice-mobile.hnxinyouhe.com/index/ rsync -avz --delete frontend/dist/* root@your-server:/www/sites/uniservice-mobile.hnxinyouhe.com/index/
# 或使用 scp
scp -r frontend/dist/* root@your-server:/www/sites/uniservice-mobile.hnxinyouhe.com/index/
``` ```
#### 2. 后端部署 ### 第三步:上传后端代码
```bash ```bash
# 上传后端代码 # 上传后端代码到服务器
rsync -avz --exclude='vendor' --exclude='runtime' backend/ root@your-server:/opt/x-server-mobile/backend/ rsync -avz --exclude='vendor' --exclude='runtime' backend/ root@your-server:/opt/x-server-mobile/backend/
```
# 在服务器上启动容器 ### 第四步:配置 1Panel Nginx
在 1Panel 面板中配置反向代理(详见下方 Nginx 配置章节)
### 第五步:启动后端容器
```bash
# 在服务器上执行
ssh root@your-server ssh root@your-server
cd /opt/x-server-mobile cd /opt/x-server-mobile
# 上传 docker-compose 和环境变量文件 # 确保配置文件已上传
# (从本地复制这些文件) ls deploy/docker-compose.prod.yml
ls deploy/.env.production
# 启动后端容器
docker-compose -f deploy/docker-compose.prod.yml up -d
# 查看容器状态
docker ps | grep x-server
docker logs -f x-server-backend-prod
``` ```
--- ---
@@ -120,7 +153,7 @@ location /api/ {
} }
# ============================================ # ============================================
# 飞书登录回调 # 飞书登录回调(必须在 API 之前匹配)
# ============================================ # ============================================
location /login { location /login {
@@ -161,7 +194,7 @@ location /feishu/card/callback {
} }
# ============================================ # ============================================
# 静态资源缓存 # 静态资源缓存(可选,提升性能)
# ============================================ # ============================================
location ~* \.(js|css|png|jpg|jpeg|gif|webp|svg|ico|woff|woff2|ttf|eot)$ { location ~* \.(js|css|png|jpg|jpeg|gif|webp|svg|ico|woff|woff2|ttf|eot)$ {
@@ -174,21 +207,25 @@ location ~* \.(js|css|png|jpg|jpeg|gif|webp|svg|ico|woff|woff2|ttf|eot)$ {
### 配置说明 ### 配置说明
| 配置项 | 说明 | | 路径 | 说明 |
|--------|------| |------|------|
| `/api/*` | 后端 API 接口,代理到 8787 端口 | | `/api/*` | 后端 API 接口,代理到 8787 端口 |
| `/login/*` | 飞书登录回调,代理到后端 | | `/login/*` | 飞书登录回调,代理到后端 |
| `/feishu/card/callback` | 飞书卡片回调,代理到后端 | | `/feishu/card/callback` | 飞书卡片回调,代理到后端 |
| 静态资源 | js/css/images 等,缓存 7 天 | | 静态资源 | js/css/images 等,缓存 7 天(可选) |
| 根路径 `/` | SPA 路由,返回 index.html | | 根路径 `/` | SPA 路由,返回 index.html |
**重要**:
- 反向代理规则要放在 `root` 指令**之前**
- 静态资源缓存规则要放在反向代理之前(优先匹配)
--- ---
## 环境变量配置 ## 环境变量配置
已创建的文件:`deploy/.env.production` ### 飞书配置(必须配置)
需要填写的配置: 编辑 `deploy/.env.production`,填写飞书应用配置:
```env ```env
# 飞书配置(必须配置) # 飞书配置(必须配置)
@@ -198,65 +235,157 @@ FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxxxxxx
FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxx FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxx
``` ```
--- ### 数据库和 Redis 配置
## 部署文件清单 已预先配置好线上环境,无需修改:
| 文件 | 说明 | 用途 | ```env
|------|------|------| # 数据库(已配置)
| `deploy/docker-compose.prod.yml` | 后端容器编排 | **线上使用** | DB_HOST=1Panel-mysql-XyxS
| `deploy/.env.production` | 线上环境变量 | **线上使用** | DB_PORT=3306
| `deploy/nginx-1panel.conf` | Nginx 配置参考 | 1Panel 配置参考 | DB_DATABASE=xserver
| `deploy/deploy-1panel.sh` | 自动部署脚本 | 简化部署流程 | DB_USERNAME=xserver
DB_PASSWORD=NsNBSQm4b2b7SzhR
**注意**:开发和线上配置完全分离,不会互相影响: # Redis(已配置)
- 开发环境使用 `docker-compose.yml` REDIS_HOST=1Panel-redis-pxdb
- 线上环境使用 `deploy/docker-compose.prod.yml` REDIS_PORT=6379
REDIS_PASSWORD=redis_FTzdM6
```
--- ---
## 验证部署 ## 使用部署脚本(可选)
如需自动化部署,可以使用部署脚本:
```bash ```bash
# 1. 检查前端 ./deploy/deploy-1panel.sh your-server-ip
```
脚本功能:
- 自动上传前端静态文件
- 自动上传后端代码
- 自动重启后端容器
**注意**:使用脚本前需要先在本地执行 `npm run build` 打包前端。
---
## 部署验证
### 1. 检查前端
```bash
# 检查首页是否可访问
curl -I https://uniservice-mobile.hnxinyouhe.com curl -I https://uniservice-mobile.hnxinyouhe.com
# 2. 检查 API # 应该返回 200 OK
```
### 2. 检查 API
```bash
# 检查 API 是否正常(需要有效的 token)
curl https://uniservice-mobile.hnxinyouhe.com/api/v1/user/info \ curl https://uniservice-mobile.hnxinyouhe.com/api/v1/user/info \
-H "Authorization: Bearer YOUR_TOKEN" -H "Authorization: Bearer YOUR_TOKEN"
```
# 3. 检查后端容器 ### 3. 检查后端容器
ssh root@server
```bash
ssh root@your-server
docker ps | grep x-server docker ps | grep x-server
# 应该看到 x-server-backend-prod 容器
docker logs -f x-server-backend-prod docker logs -f x-server-backend-prod
# 查看后端日志
```
### 4. 检查 Nginx 日志
```bash
# 在 1Panel 面板中查看
# 或者直接查看日志文件
tail -f /www/sites/uniservice-mobile.hnxinyouhe.com/log/access.log
``` ```
--- ---
## 常见问题 ## 常见问题
### Q: 前端显示但 API 调用失败? ### Q1: 前端显示但 API 调用 404?
A: 检查 1Panel Nginx 配置是否添加了 `/api/` 的反向代理规则。 **A**: 检查 1Panel Nginx 配置中是否添加了 `/api/` 的反向代理规则。
### Q: 后端容器启动失败? ### Q2: 后端容器启动失败?
A: 检查 `deploy/docker-compose.prod.yml` 中的数据库和 Redis 容器名称是否正确。 **A**: 检查:
- 数据库和 Redis 容器是否运行
- Docker 网络 `1panel-network` 是否存在
- 容器日志:`docker logs x-server-backend-prod`
### Q: 飞书登录失败? ### Q3: 飞书登录失败?
A: 检查 `/login/*` 的反向代理规则是否已添加。 **A**: 检查 `/login/*` 的反向代理规则是否已添加。
### Q4: 静态资源加载 404?
**A**: 确认前端上传到了正确的目录:`/www/sites/uniservice-mobile.hnxinyouhe.com/index/`
### Q5: 前端页面空白?
**A**: 检查:
- 确认前端打包成功:`ls frontend/dist/` 是否有 `index.html`
- 检查浏览器控制台是否有错误
---
## 开发环境 vs 生产环境
| 项目 | 开发环境 | 生产环境 |
|------|---------|---------|
| **前端** | `npm run dev` (Vite 开发服务器) | `npm run build` + 上传静态文件 |
| **后端** | `docker-compose.yml` | `deploy/docker-compose.prod.yml` |
| **API 地址** | `http://localhost:8787/api/v1` | `/api/v1` (相对路径) |
| **数据** | 本地数据库或开发数据库 | 线上数据库 |
--- ---
## 回滚操作 ## 回滚操作
```bash ### 前端回滚
# 使用备份回滚
ssh root@server
cd /www/sites/uniservice-mobile.hnxinyouhe.com
cp -r backup/YYYYMMDD_HHMMSS/* index/
# 重启后端容器到指定版本 ```bash
# 从之前的备份恢复
ssh root@your-server
cp -r /www/sites/uniservice-mobile.hnxinyouhe.com/backup/YYYYMMDD_HHMMSS/* \
/www/sites/uniservice-mobile.hnxinyouhe.com/index/
```
### 后端回滚
```bash
ssh root@your-server
cd /opt/x-server-mobile cd /opt/x-server-mobile
git log # 查看提交历史
git checkout <commit-id> # 切换到指定版本 # 切换到之前的提交
git log --oneline
git checkout <commit-id>
# 重新构建并启动
docker-compose -f deploy/docker-compose.prod.yml up -d --build docker-compose -f deploy/docker-compose.prod.yml up -d --build
``` ```
---
## 文件清单
部署相关的所有文件:
| 文件 | 用途 |
|------|------|
| `deploy/docker-compose.prod.yml` | 线上后端容器配置 |
| `deploy/.env.production` | 线上环境变量 |
| `deploy/nginx-1panel.conf` | Nginx 配置参考 |
| `deploy/deploy-1panel.sh` | 自动部署脚本 |
| `docs/DEPLOY_ONLINE_GUIDE.md` | 本文档 |
**注意**:
- 开发环境配置(`docker-compose.yml`)与线上环境完全分离
- 部署文件都在 `deploy/` 目录,不会影响开发环境配置