当前位置: 首页 > news >正文

使用CI/CD部署项目(前端Nextjs)

写在前面:在github上使用CI/CD部署Nextjs项目,具体配置可以按照自己的实际的修改

这是我的项目配置,仅供参考
在这里插入图片描述
后端项目可以参考:使用CI/CD部署后端项目

正文开始

项目名(PROJECT_NAME)- CI/CD 部署指南(GitHub Actions + SSH + PM2)

本项目已内置基于 GitHub Actions 的 CI/CD。它会在 main 分支有变更或手动触发时:

  • 安装依赖并构建 Next.js 产物
  • 通过 SCP 将构建产物上传至服务器指定目录
  • 通过 SSH 调用 PM2 平滑重载运行中的服务

1. 文件位置

  • 工作流文件(部署文件示例已经放到文末):.github/workflows/deploy.yml

2. 前置条件

  • 服务器已安装 Node.js 18.x 与 npm(与工作流一致)
  • 服务器已安装 PM2:npm i -g pm2
  • 服务器部署目录存在且对 SSH 用户可写,例如:/var/www/PROJECT_NAME

3. 仓库 Secrets 配置

在 GitHub → 仓库 → Settings → Secrets and variables → Actions 中添加:

必填

  • SSH_HOST:服务器 IP/域名
  • SSH_USER:SSH 用户名
  • SSH_PORT:SSH 端口(如 22)
  • SSH_PASSWORD:SSH 登录密码(如改用密钥见文末)
  • REMOTE_PATH:服务器部署根目录(例如 /var/www/PROJECT_NAME

可选

  • ENV_FILE_CONTENTS:用于生成 .env.production 的完整文本。例如:
    NEXT_PUBLIC_API_URL=https://api.your-domain.com
    NEXT_PUBLIC_LANGUAGE=en
    NEXT_PUBLIC_WALLETCONNECT_ID=xxxxxxx
    

说明

  • 工作流会在“构建前”把 ENV_FILE_CONTENTS 写为 .env.production,确保 NEXT_PUBLIC_* 变量参与 Next.js 打包。

4. 服务器目录结构(默认)

工作流会将 release.tar.gz 上传至 REMOTE_PATH 并解压到 REMOTE_PATH/current 下:

REMOTE_PATH/└── current/├── .next/├── public/├── ecosystem.config.js├── package.json├── package-lock.json├── .env.production (可选)└── ...

5. 触发部署

  • 自动:向 main 分支推送代码会自动触发
  • 手动:GitHub → Actions → 选择 CI/CD DeployRun workflow → 选择 main

6. 运行流程概览

  1. Checkout 代码
  2. 使用 Node 18 安装依赖(包含 devDependencies)并构建
  3. 压缩构建产物与必要文件为 release.tar.gz
  4. 通过 SCP 上传到服务器 REMOTE_PATH
  5. 通过 SSH:
    • 解压到 REMOTE_PATH/current
    • 写入 .env.production(如提供)
    • npm ci --omit=dev
    • pm2 startOrReload ecosystem.config.js --env production

7. PM2 常用命令

pm2 ls                       # 查看进程
pm2 logs --lines 100         # 查看日志
pm2 restart <name|id>        # 重启
pm2 stop <name|id>           # 停止
pm2 delete <name|id>         # 删除

8. 回滚思路(简易)

当前流程将产物解压到 current/。若需要回滚,推荐:

  • 在服务器保留历史版本目录(可扩展工作流增加 releases/ 与符号链接),或
  • 临时将上一份稳定包重新上传并覆盖 current/pm2 reload

9. 常见问题与排查

  • 构建期报 Cannot find module 'xxx':确保安装步骤包含 devDependencies(本工作流已处理)。
  • SCP/SSH 失败:检查 SSH_HOST/USER/PORT/PASSWORD 是否正确,服务器防火墙、安全组、端口开放情况。
  • 权限问题:确保 REMOTE_PATHSSH_USER 可写,如需:sudo chown -R <user>:<user> /var/www/PROJECT_NAME
  • 环境变量不生效:确认 ENV_FILE_CONTENTS 已填写,变量名与代码中一致(例如 NEXT_PUBLIC_API_URL)。

10. 切换为 SSH 密钥登录(可选,更安全)

  1. 本地生成密钥:
ssh-keygen -t ed25519 -C "deploy" -N "" -f ~/.ssh/PROJECT_NAME_deploy
  1. ~/.ssh/PROJECT_NAME_deploy.pub 追加到服务器 ~/.ssh/authorized_keys
  2. 在仓库 Secrets 新增:SSH_KEY(粘贴私钥全文),并把工作流中 password: ${{ secrets.SSH_PASSWORD }} 改为 key: ${{ secrets.SSH_KEY }}(scp/ssh 两处)

11. 调整 Node 版本

  • 服务器与工作流默认使用 Node 18。如需升级:同时升级服务器 Node 与工作流的 actions/setup-node 版本号,保持一致。

如需灰度、分环境(staging/prod)或保留多版本回滚,请联系维护者扩展工作流(增加 environmentsreleases 目录策略)。

附:示例工作流(脱敏,含注释与可改项)

# 工作流名称,会显示在 Actions 列表中
name: CI/CD Deployon:# 推送到 main 分支时自动触发(如需改分支,请改这里)push:branches:- main# 允许在 Actions 页面手动触发workflow_dispatch:permissions:contents: readjobs:build-and-deploy:runs-on: ubuntu-latest# Job 级别环境变量:默认生产。构建阶段会临时切到 development 以安装 dev 依赖env:NODE_ENV: productionsteps:# 1) 拉取代码- name: Checkout repositoryuses: actions/checkout@v4# 2) 选择 Node 版本(与服务器一致;可改为 20 等)- name: Use Node.js 18uses: actions/setup-node@v4with:node-version: 18cache: npm# 3) 写入 .env.production(可选)#    值来自仓库 Secret: ENV_FILE_CONTENTS(整段文本,包含多行 KEY=VALUE)- name: Create .env.production from secrets (if provided)env:ENV_FILE_CONTENTS: ${{ secrets.ENV_FILE_CONTENTS }}run: |if [ -n "$ENV_FILE_CONTENTS" ]; thenprintf "%s" "$ENV_FILE_CONTENTS" > .env.productionfi# 4) 安装依赖(包含 devDependencies,避免构建缺包)- name: Install dependencies (with fallback, include dev deps)env:NPM_CONFIG_PRODUCTION: "false"NODE_ENV: developmentrun: |npm ci || npm install --legacy-peer-deps# 5) 构建(生产环境)- name: Buildenv:NODE_ENV: productionrun: npm run build# 6) 仅打包需要的文件(如需额外文件,按需在此补充)- name: Prepare artifact (ship only what is needed)run: |tar -czf release.tar.gz \.next \public \package.json \package-lock.json \next.config.js \ecosystem.config.js \tsconfig.json \postcss.config.js \tailwind.config.js# 7) 上传产物到服务器(以下 5 个值均来自仓库 Secrets)#    - SSH_HOST:服务器 IP/域名(需改为你的)#    - SSH_USER:SSH 用户名(需改为你的)#    - SSH_PASSWORD:SSH 密码(如改用密钥见文档)#    - SSH_PORT:SSH 端口(默认 22,可按需修改)#    - REMOTE_PATH:部署目录(需改为你的,例如 /var/www/your-app)- name: Upload artifact to serveruses: appleboy/scp-action@v0.1.7with:host: ${{ secrets.SSH_HOST }}username: ${{ secrets.SSH_USER }}password: ${{ secrets.SSH_PASSWORD }}port: ${{ secrets.SSH_PORT }}source: "release.tar.gz"target: ${{ secrets.REMOTE_PATH }}# 8) 服务器上解压、装产线依赖并用 PM2 启动/热重载- name: Deploy on server (extract, install prod deps, reload pm2)uses: appleboy/ssh-action@v1.0.3with:host: ${{ secrets.SSH_HOST }}username: ${{ secrets.SSH_USER }}password: ${{ secrets.SSH_PASSWORD }}port: ${{ secrets.SSH_PORT }}script_stop: truescript: |set -ecd ${{ secrets.REMOTE_PATH }}mkdir -p currentmv release.tar.gz current/cd currenttar -xzf release.tar.gzrm -f release.tar.gz# 二次兜底:如提供了 ENV_FILE_CONTENTS,这里也会写入(与构建前一致)if [ ! -z "${{ secrets.ENV_FILE_CONTENTS }}" ]; thenecho "${{ secrets.ENV_FILE_CONTENTS }}" > .env.productionfi# 服务器仅安装生产依赖,减小体积npm ci --omit=dev# 使用 PM2 平滑重载;若无进程则创建if command -v pm2 >/dev/null 2>&1; thenpm2 startOrReload ecosystem.config.js --env production || pm2 start ecosystem.config.js --env productionpm2 saveelsenpm i -g pm2pm2 start ecosystem.config.js --env productionpm2 savefi

文章转载自:

http://yXg38yWJ.wtLyr.cn
http://v0K6RJOJ.wtLyr.cn
http://ilqnn8hp.wtLyr.cn
http://IXvrMuUo.wtLyr.cn
http://pKZaZrEw.wtLyr.cn
http://kutKshPx.wtLyr.cn
http://vUrFzuFb.wtLyr.cn
http://dLlzucSH.wtLyr.cn
http://ZmIdJxY0.wtLyr.cn
http://KLwXtQpT.wtLyr.cn
http://ubSFRWJq.wtLyr.cn
http://hUNBC0OI.wtLyr.cn
http://DX8rP9ix.wtLyr.cn
http://kvqQeMb4.wtLyr.cn
http://gLXNjSJh.wtLyr.cn
http://G881e8d1.wtLyr.cn
http://C8a5zf3R.wtLyr.cn
http://IZV5lLGh.wtLyr.cn
http://gi3R0G3l.wtLyr.cn
http://ai6bu7z1.wtLyr.cn
http://cyjolWFC.wtLyr.cn
http://20EQHO4i.wtLyr.cn
http://Nq3pz90E.wtLyr.cn
http://z3aYTNbN.wtLyr.cn
http://WJqQ0Yd2.wtLyr.cn
http://GRH9J9XA.wtLyr.cn
http://v9p7OpRb.wtLyr.cn
http://hHcpBJwW.wtLyr.cn
http://1cbTOfjb.wtLyr.cn
http://vuR6zcTm.wtLyr.cn
http://www.dtcms.com/a/368937.html

相关文章:

  • Git常用操作(2)
  • LeetCode 刷题【65. 有效数字】
  • Android,jetpack Compose模仿QQ侧边栏
  • 让语言模型自我进化:探索 Self-Refine 的迭代反馈机制
  • Kubernetes(k8s) po 配置持久化挂载(nfs)
  • 支持二次开发的代练App源码:订单管理、代练监控、安全护航功能齐全,一站式解决代练护航平台源码(PHP+ Uni-app)
  • proble1111
  • Ubuntu 24.04.2安装k8s 1.33.4 配置cilium
  • nextcyber——暴力破解
  • Process Explorer 学习笔记(第三章3.2.3):工具栏与参考功能
  • C++两个字符串的结合
  • c51串口通信原理及实操
  • Java垃圾回收算法详解:从原理到实践的完整指南
  • MongoDB 6.0 新特性解读:时间序列集合与加密查询
  • IAR借助在瑞萨RH850/U2A MCU MCAL支持,加速汽车软件开发
  • 状压 dp --- 棋盘覆盖问题
  • 机器学习周报十二
  • 力扣:2322. 从树中删除边的最小分数
  • 人工智能常见分类
  • C++ 音视频开发常见面试题及答案汇总
  • C/C++ Linux系统编程:线程控制详解,从线程创建到线程终止
  • swoole 中 Coroutine\WaitGroup 和channel区别和使用场景
  • HDFS架构核心
  • Python的语音配音软件,使用edge-tts进行文本转语音,支持多种声音选择和语速调节
  • 每周资讯 | 中国游戏市场将在2025年突破500亿美元;《恋与深空》收入突破50亿元
  • 别再手工缝合API了!开源LLMOps神器LMForge,让你像搭积木一样玩转AI智能体!
  • 问卷系统项目自动化测试
  • 事务管理的选择:为何 @Transactional 并非万能,TransactionTemplate 更值得信赖
  • React Fiber 风格任务调度库
  • Sentinel和Cluster,到底该怎么选?