CentOS7 + 宝塔 Nginx + Java Jar:GitHub Actions 自动部署步骤
摘要本文详细介绍了使用 GitHub Actions 实现前后端项目自动化部署的完整流程。从服务器环境准备、SSH 密钥生成、GitHub Secrets 配置到部署文件编写、首次部署和日常发布提供了全栈部署的一站式解决方案。文章包含具体的脚本示例、配置步骤和故障排查方法帮助开发者快速搭建自动化部署流水线。一、服务器准备确认前端站点目录、管理端站点目录、后端目录已存在用户端/www/wwwroot/www.mocsim.com管理端/www/wwwroot/admin.mocsim.com后端/opt确认服务器已安装 Java 17可用命令java -version确认后端 jar 名称为xxxx-xxxx-1.0.0.jar将restart-backend.sh放到/opt/restart-backend.sh#!/bin/bash # 示例后端重启脚本可直接复制后按自己项目改 jar 名 # 建议放到服务器后端目录例如: /opt/my-app/restart-backend.sh # 与 jar 同目录例如: /opt/my-app/my-app-1.0.0.jar # 用法: bash /opt/my-app/restart-backend.sh # # Windows 传到 Linux 后若报 set: pipefail先执行: # sed -i s/\r$// restart-backend.sh set -euo pipefail APP_DIR$(cd $(dirname $0) pwd) 示例 jar 名按实际修改 JAR_NAME${JAR_NAME:-my-app-1.0.0.jar} JAR_PATH$APP_DIR/$JAR_NAME PID_FILE$APP_DIR/app.pid LOG_FILE$APP_DIR/app.log JAVA_BIN${JAVA_BIN:-java} 默认生产环境可覆盖: SPRING_PROFILEtest bash restart-backend.sh SPRING_PROFILE${SPRING_PROFILE:-prod} if [[ ! -f $JAR_PATH ]]; then echo ERROR: jar not found: $JAR_PATH exit 1 fi stop_old() { if [[ -f $PID_FILE ]]; then OLD_PID$(cat $PID_FILE || true) if [[ -n ${OLD_PID} ]] kill -0 $OLD_PID 2/dev/null; then echo Stopping pid $OLD_PID ... kill $OLD_PID || true for _ in $(seq 1 20); do kill -0 $OLD_PID 2/dev/null || break sleep 0.5 done if kill -0 $OLD_PID 2/dev/null; then echo Force kill $OLD_PID kill -9 $OLD_PID || true fi fi rm -f $PID_FILE fi pkill -f $JAR_NAME 2/dev/null || true sleep 1 } start_new() { echo Starting $JAR_PATH (profile$SPRING_PROFILE) ... cd $APP_DIR nohup $JAVA_BIN -jar $JAR_NAME --spring.profiles.active$SPRING_PROFILE $LOG_FILE 21 echo $! $PID_FILE echo Started pid $(cat $PID_FILE), log: $LOG_FILE } stop_old start_new echo Backend restart done.执行chmod x /opt/restart-backend.sh sed -i s/\r$// /opt/restart-backend.sh手动测试重启bash /opt/restart-backend.sh tail -n 50 /opt/app.log确认日志出现The following 1 profile is active: prod新建 .github/workflows/deploy.yml 示例如下# 示例GitHub Actions 自动部署可直接复制后按自己项目改路径 文件建议放在仓库.github/workflows/deploy.yml 需要在 GitHub → Settings → Secrets and variables → Actions 配置 DEPLOY_HOST 服务器公网 IP DEPLOY_USER SSH 用户如 root DEPLOY_PORT SSH 端口如 22 DEPLOY_SSH_KEY 部署用私钥全文 FRONT_REMOTE_PATH 用户端站点目录如 /www/wwwroot/www.example.com ADMIN_REMOTE_PATH 管理端站点目录如 /www/wwwroot/admin.example.com BACKEND_REMOTE_DIR 后端目录如 /opt/my-app name: Deploy on: push: branches: [main] workflow_dispatch: concurrency: group: deploy-production cancel-in-progress: true jobs: build-and-deploy: runs-on: ubuntu-latest env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} FRONT_REMOTE_PATH: ${{ secrets.FRONT_REMOTE_PATH }} ADMIN_REMOTE_PATH: ${{ secrets.ADMIN_REMOTE_PATH }} BACKEND_REMOTE_DIR: ${{ secrets.BACKEND_REMOTE_DIR }} steps: - name: Checkout uses: actions/checkoutv4 - name: Setup Node.js uses: actions/setup-nodev4 with: node-version: 20 name: Setup Java uses: actions/setup-javav4 with: distribution: temurin java-version: 17 cache: maven cache-dependency-path: backend/pom.xml 示例用户端前端目录 frontend/web name: Build storefront working-directory: frontend/web run: | if [ -f package-lock.json ]; then npm ci; else npm install; fi npm run build 示例管理端前端目录 frontend/admin name: Build admin working-directory: frontend/admin run: | if [ -f package-lock.json ]; then npm ci; else npm install; fi npm run build 示例后端用 -Pprod 打包产物名为 my-app-1.0.0.jar name: Build backend jar working-directory: backend run: mvn -B -Pprod -DskipTests package name: Prepare SSH run: | set -euo pipefail PORT${DEPLOY_PORT:-22} mkdir -p ~/.ssh echo $DEPLOY_SSH_KEY gt; ~/.ssh/deploy_key chmod 600 ~/.ssh/deploy_key ssh-keyscan -p $PORT -H $DEPLOY_HOST gt;gt; ~/.ssh/known_hosts 2gt;/dev/null || true echo SSH_PORT$PORT gt;gt; $GITHUB_ENV env: DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} name: Upload storefront run: | RSYNC_SSHssh -i ~/.ssh/deploy_key -p ${SSH_PORT} -o StrictHostKeyCheckingaccept-new 宝塔站点常有受保护的 .user.ini--delete 删不掉会触发 rsync code 23 rsync -avz --delete --exclude.user.ini --exclude.htaccess --exclude.well-known --no-owner --no-group --no-perms -e $RSYNC_SSH frontend/web/dist/ ${DEPLOY_USER}${DEPLOY_HOST}:${FRONT_REMOTE_PATH}/ name: Upload admin run: | RSYNC_SSHssh -i ~/.ssh/deploy_key -p ${SSH_PORT} -o StrictHostKeyCheckingaccept-new rsync -avz --delete --exclude.user.ini --exclude.htaccess --exclude.well-known --no-owner --no-group --no-perms -e $RSYNC_SSH frontend/admin/dist/ ${DEPLOY_USER}${DEPLOY_HOST}:${ADMIN_REMOTE_PATH}/ name: Upload backend jar and restart script run: | rsync -avz -e ssh -i ~/.ssh/deploy_key -p ${SSH_PORT} -o StrictHostKeyCheckingaccept-new backend/target/my-app-1.0.0.jar deploy/restart-backend.sh ${DEPLOY_USER}${DEPLOY_HOST}:${BACKEND_REMOTE_DIR}/ ssh -i ~/.ssh/deploy_key -p ${SSH_PORT} -o StrictHostKeyCheckingaccept-new ${DEPLOY_USER}${DEPLOY_HOST} chmod x ${BACKEND_REMOTE_DIR}/restart-backend.sh amp;amp; sed -i s/\r$// ${BACKEND_REMOTE_DIR}/restart-backend.sh name: Restart backend run: | ssh -i ~/.ssh/deploy_key -p ${SSH_PORT} -o StrictHostKeyCheckingaccept-new ${DEPLOY_USER}${DEPLOY_HOST} bash ${BACKEND_REMOTE_DIR}/restart-backend.sh二、生成部署 SSH 密钥在服务器执行mkdir -p ~/.ssh chmod 700 ~/.ssh ssh-keygen -t ed25519 -C github-deploy -f ~/.ssh/mocbase_deploy -N cat ~/.ssh/mocbase_deploy.pub ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ~/.ssh/mocbase_deploy查看私钥稍后填到 GitHub Secretscat ~/.ssh/mocbase_deploy三、配置 GitHub Secrets打开仓库地址https://github.com/你的用户名/你的仓库名/settings/secrets/actions点击New repository secret依次新增以下 7 个NameSecret 示例DEPLOY_HOST服务器公网 IPDEPLOY_USERrootDEPLOY_PORT22DEPLOY_SSH_KEYcat ~/.ssh/mocbase_deploy的完整私钥FRONT_REMOTE_PATH/www/wwwroot/www.xxxxx.comADMIN_REMOTE_PATH/www/wwwroot/xxxx.xxxxx.comBACKEND_REMOTE_DIR/opt示例如下四、仓库部署文件仓库根目录需有示例在服务器准备中.github/workflows/deploy.yml deploy/restart-backend.sh五、提交并首次部署提交并推送git push origin main打开https://github.com/你的用户名/你的仓库名/actions查看Deploy工作流是否成功绿色勾若失败在Upload storefront且提示 connection timed out检查DEPLOY_HOST是否填错公网 IP、安全组/宝塔是否放行 SSH 端口若失败为 rsync code 23确认已排除.user.ini等宝塔文件成功示例六、日常发布本地改完代码后执行git push origin main打开 Actions 查看Deploy是否成功强刷前台和管理端页面验证后端验证grep -i profile is active /opt/app.log | tail -5tail -n 30 /opt/app.log七、说明服务器不需要安装 Maven、Node构建在 GitHub Actions 云端完成服务器只接收产物并重启前端替换静态文件基本无感后端java -jar重启会有短暂中断