deploy-prod.sh 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #!/bin/bash
  2. #
  3. # 有声书项目 - 生产环境部署脚本
  4. # 部署到 8.159.134.106:/data/ai/audio
  5. # 前端域名: book.rrbrr.com
  6. # 后端 API 域名: bookapi.rrbrr.com
  7. # 后端端口: 22622
  8. set -e
  9. REMOTE_HOST="8.159.134.106"
  10. REMOTE_PATH="/data/ai/audio"
  11. LOCAL_PROJECT="$(cd "$(dirname "$0")" && pwd)"
  12. SSH_KEY="$HOME/.ssh/id_rsa"
  13. SSH_PORT="22622"
  14. echo "=== 有声书项目 - 生产环境部署 ==="
  15. echo "时间: $(date)"
  16. echo "主机: $REMOTE_HOST"
  17. echo "路径: $REMOTE_PATH"
  18. echo "前端: book.rrbrr.com"
  19. echo "后端: bookapi.rrbrr.com:22622"
  20. echo ""
  21. # 1. 构建前端(后端使用已有的 dist)
  22. echo "=== 1. 构建前端 ==="
  23. cd "$LOCAL_PROJECT/my-uniapp-vue3"
  24. npm run build:h5
  25. echo "前端构建完成"
  26. cd "$LOCAL_PROJECT"
  27. # 2. 同步文件到服务器
  28. echo ""
  29. echo "=== 2. 同步文件到服务器 ==="
  30. # 创建临时目录
  31. TEMP_DIR="/tmp/deploy_audio_$(date +%Y%m%d_%H%M%S)"
  32. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST "mkdir -p $TEMP_DIR"
  33. # 本地临时目录
  34. mkdir -p "$LOCAL_PROJECT/tmp"
  35. # 打包后端(使用已有的 dist,打包所有必要文件,排除 node_modules, .git, *.ts)
  36. echo "打包后端文件..."
  37. cd "$LOCAL_PROJECT/server"
  38. tar --exclude='node_modules' --exclude='.git' --exclude='test-*.js' -czf "$LOCAL_PROJECT/tmp/server.tar.gz" .
  39. cd "$LOCAL_PROJECT"
  40. # 打包前端(只打包 build/h5 目录内容,对接 nginx root)
  41. echo "打包前端文件..."
  42. cd "$LOCAL_PROJECT/my-uniapp-vue3/dist/build/h5"
  43. tar -czf "$LOCAL_PROJECT/tmp/frontend.tar.gz" .
  44. cd "$LOCAL_PROJECT"
  45. # 上传到服务器
  46. echo "上传后端..."
  47. scp -i "$SSH_KEY" -P "$SSH_PORT" "$LOCAL_PROJECT/tmp/server.tar.gz" root@$REMOTE_HOST:$TEMP_DIR/
  48. echo "上传前端..."
  49. scp -i "$SSH_KEY" -P "$SSH_PORT" "$LOCAL_PROJECT/tmp/frontend.tar.gz" root@$REMOTE_HOST:$TEMP_DIR/
  50. # 清理本地临时文件
  51. rm -rf "$LOCAL_PROJECT/tmp"
  52. # 3. 在服务器上安装 Node.js(如需要)
  53. echo ""
  54. echo "=== 3. 检查并安装 Node.js ==="
  55. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST << 'ENDSSH'
  56. set -e
  57. # 检查 Node.js 是否已安装
  58. if ! command -v node &> /dev/null; then
  59. echo "安装 Node.js 20.x..."
  60. curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
  61. dnf install -y nodejs
  62. fi
  63. echo "Node.js 版本: $(node --version)"
  64. echo "npm 版本: $(npm --version)"
  65. ENDSSH
  66. # 4. 在服务器上执行部署
  67. echo ""
  68. echo "=== 4. 执行服务器部署 ==="
  69. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST << 'ENDSSH'
  70. set -e
  71. TEMP_DIR=$(ls -td /tmp/deploy_audio_* | head -1)
  72. REMOTE_PATH="/data/ai/audio"
  73. BACKUP_DIR="$REMOTE_PATH/backup_$(date +%Y%m%d_%H%M%S)"
  74. echo "创建备份..."
  75. mkdir -p $BACKUP_DIR
  76. if [ -d "$REMOTE_PATH/server" ]; then
  77. cp -r $REMOTE_PATH/server $BACKUP_DIR/ 2>/dev/null || true
  78. fi
  79. if [ -d "$REMOTE_PATH/frontend" ]; then
  80. cp -r $REMOTE_PATH/frontend $BACKUP_DIR/ 2>/dev/null || true
  81. fi
  82. echo "解压文件到临时目录..."
  83. cd $TEMP_DIR
  84. rm -rf server frontend
  85. mkdir -p server frontend
  86. tar -xzf server.tar.gz -C server/
  87. tar -xzf frontend.tar.gz -C frontend/
  88. echo "部署后端到目标目录..."
  89. rm -rf $REMOTE_PATH/server
  90. mv server $REMOTE_PATH/
  91. echo "部署前端到 nginx 目录..."
  92. rm -rf /data/ai/frontend/build/h5/*
  93. mkdir -p /data/ai/frontend/build/h5
  94. cp -r frontend/* /data/ai/frontend/build/h5/
  95. rm -rf frontend
  96. echo "验证关键文件..."
  97. ls -la $REMOTE_PATH/server/dist/ 2>/dev/null || echo "dist 目录不存在"
  98. ls -la $REMOTE_PATH/server/prisma/ 2>/dev/null || echo "prisma 目录不存在"
  99. echo "安装后端依赖..."
  100. cd $REMOTE_PATH/server
  101. npm install --production
  102. echo "复制生产环境配置..."
  103. cp $REMOTE_PATH/server/.env.production $REMOTE_PATH/server/.env
  104. echo "生成 Prisma Client..."
  105. npx prisma generate
  106. echo "清理临时文件..."
  107. rm -rf $TEMP_DIR
  108. echo "服务器部署完成!"
  109. ENDSSH
  110. # 5. 配置 Nginx
  111. echo ""
  112. echo "=== 5. 配置 Nginx ==="
  113. echo "Nginx 配置由宝塔面板管理,请手动配置:"
  114. echo "- book.rrbrr.com: /www/server/panel/vhost/nginx/book.rrbrr.com.conf"
  115. echo "- bookapi.rrbrr.com: /www/server/panel/vhost/nginx/bookapi.rrbrr.com.conf"
  116. echo "后端端口: 3100"
  117. # 6. 启动后端服务
  118. echo ""
  119. echo "=== 6. 启动后端服务 ==="
  120. ssh -i "$SSH_KEY" -p "$SSH_PORT" root@$REMOTE_HOST << 'ENDSSH'
  121. set -e
  122. cd /data/ai/audio/server
  123. # 安装 PM2(如果没有)
  124. if ! command -v pm2 &> /dev/null; then
  125. echo "安装 PM2..."
  126. npm install -g pm2
  127. fi
  128. # 停止旧服务
  129. pm2 delete server 2>/dev/null || true
  130. # 设置环境变量(使用 3100 端口,避免与 SSH 22622 冲突)
  131. export SERVER_PORT=3100
  132. # 启动服务
  133. pm2 start dist/app.js --name server --env production
  134. # 保存并设置开机启动
  135. pm2 save
  136. pm2 startup
  137. echo "后端服务已启动 (端口 22622)!"
  138. ENDSSH
  139. echo ""
  140. echo "=== 部署完成 ==="
  141. echo "前端地址: http://book.rrbrr.com"
  142. echo "后端 API: http://bookapi.rrbrr.com/api"
  143. echo "健康检查: http://bookapi.rrbrr.com/health"