使用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://www.pswp.cn/news/921701.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/921701.shtml
英文地址,請注明出處:http://en.pswp.cn/news/921701.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java全棧工程師面試實錄:從基礎到實戰的全面解析

Java全棧工程師面試實錄&#xff1a;從基礎到實戰的全面解析 面試官&#xff1a;李明&#xff08;資深技術負責人&#xff09; 應聘者&#xff1a;張宇&#xff08;28歲&#xff0c;碩士學歷&#xff0c;5年開發經驗&#xff09; 第一輪&#xff1a;Java語言與JVM基礎 李明&…

C#中解析XML時遇到注釋節點報錯

在C#中解析XML時遇到注釋節點報錯的問題&#xff0c;這是因為XML注釋節點&#xff08;<!-- -->&#xff09;是特殊的節點類型。當遍歷XML節點時&#xff0c;注釋節點也會被包含在內&#xff0c;但它們不能像普通元素節點那樣處理。 解決方案 方法1&#xff1a;跳過注釋節…

9.3深度循環神經網絡

目前為止&#xff0c;只討論了具有一個單向隱藏層的循環神經網絡&#xff0c;其中隱變量和觀測值域具體的函數形式的交互方式是相當隨意的。只要交互類型建模具有足夠的靈活性&#xff0c;不是一個單問題。然而&#xff0c;對一個單層來說&#xff0c;可能具有相當的挑戰性。之…

CSS in JS 的演進:Styled Components, Emotion 等的深度對比與技術選型指引

CSS in JS 的演進&#xff1a;Styled Components, Emotion 等的深度對比與技術選型指引在現代前端開發中&#xff0c;組件化思維已成為主流&#xff0c;而如何科學、高效地管理組件的樣式&#xff0c;也隨之成為了一個重要議題。CSS in JS&#xff08;JS中的CSS&#xff09;應運…

【正則表達式】 正則表達式的分組和引用

?? 個人主頁:(時光煮雨) ?? 高質量專欄:vulnhub靶機滲透測試 ?? 希望得到您的訂閱和支持~ ?? 創作高質量博文(平均質量分95+),分享更多關于網絡安全、Python領域的優質內容!(希望得到您的關注~) ??目錄?? 前言 ??一、基本語法 ??二、分組類型 ??2.1.…

Grafana 導入儀表盤失敗:從日志排查到解決 max\_allowed\_packet 問題

問題背景 近期在為項目搭建一套基于 Prometheus 和 Grafana 的可觀測性體系。在完成基礎部署后&#xff0c;我準備導入一個功能相對復雜的官方儀表盤模板&#xff0c;以便快速監控各項指標。然而&#xff0c;當上傳儀表盤的 JSON 文件并點擊保存時&#xff0c;Grafana 界面卻反…

java對接物聯網設備(一)——使用okhttp網絡工具框架對接標準API接口

當前無論是在互聯網領域&#xff0c;還是物聯網項目下&#xff0c;亦或者各類應用類軟件&#xff0c;基于http標準接口的對接是目前市面上最常見也是最簡單的數據交互方式之一&#xff0c;甚至可以說是最流行的&#xff0c;因為它不依賴的各種插件或者服務。 開發者或者提供服…

版本管理系統與平臺(權威資料核對、深入解析、行業選型與國產平臺補充)

本文是一篇基于公開權威資料&#xff08;官方文檔、產品頁、廠商技術文章與技術社區討論&#xff09;重新檢索、核對后撰寫的詳盡博文。內容覆蓋&#xff1a;版本控制基礎、主流 VCS 工具深度比較、常見托管/協作平臺&#xff08;含中國本土平臺&#xff1a;Gitee / GitCode / …

計算機畢設選題:基于Python+Django的B站數據分析系統的設計與實現【源碼+文檔+調試】

精彩專欄推薦訂閱&#xff1a;在 下方專欄&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主頁&#xff1a;計算機畢設木哥&#x1f525; &#x1f496; 文章目錄 一、項目介紹二…

Easy ES技術詳解

從Java代碼示例到高級特性 框架介紹 Easy-Es 是一款以 “簡化 Elasticsearch 操作的 ORM 框架” 為核心定位的開源工具&#xff0c;旨在通過低代碼設計降低 Elasticsearch 的使用門檻。作為國內 Top1 Elasticsearch 搜索引擎框架&#xff0c;其最顯著的優勢在于大幅縮減代碼量…

【51單片機】【protues仿真】基于51單片機停車場的車位管理系統

目錄 一、主要功能 二、使用步驟 三、硬件資源 四、軟件設計 五、實驗現象 一、主要功能 1、LCD1602液晶顯示 2、統計并顯示停車場現有車輛數和已停放過車輛數 3、按鍵設置總車位數以及剩余車位數 4、統計并顯示累計駛入和累計駛出車輛數 5、用16個LED燈模擬停車位 6、車…

【Python】S1 基礎篇 P4 if 語句指南

目錄簡單示例條件測試檢查是否相等與不等檢查多個條件檢查特定的值是否在/不在列表中布爾表達式if語句簡單的if語句if-else語句if-elif-else語句使用if語句處理列表檢查特殊元素確定列表非空使用多個列表總結if 語句是Python編程中最基本也是最重要的控制結構之一。它允許程序根…

【實戰中提升自己】內網安全部署之STP的安全技術部署

1 1拓撲 「模擬器、工具合集」復制整段內容 鏈接&#xff1a;https://docs.qq.com/sheet/DV0xxTmFDRFVoY1dQ?tab7ulgil1 STP的安全技術部署 說明&#xff1a;為什么需要注意STP的安全呢&#xff0c;在二層中其實存在很多不安全的因素&#xff0c;物理上…

GEM5學習(5): ARM 架構功耗仿真

運行腳本基于gem5提供的腳本&#xff0c;啟動功耗仿真。實際工作中應該不會用gem5進行功耗的仿真吧&#xff0c;Cadence和Synopsys好像都有配套的的功耗建模工具。事先要配置好 IMG_ROOT的環境變量./build/ARM/gem5.opt configs/example/arm/fs_power.py \--caches \--bootl…

【Python基礎】 19 Rust 與 Python if 語句對比筆記

一、基本語法對比 Rust if 語句 // 基本形式 let number 7;if number < 5 {println!("condition was true"); } else {println!("condition was false"); }// 多條件 else if if number % 4 0 {println!("number is divisible by 4"); } el…

Vue項目_項目配置腳本代碼詳細講解

Vue項目代碼詳細講解 1. jsconfig.json - JavaScript配置文件 {"compilerOptions": { // 編譯器選項配置"target": "es5", // 編譯目標&#xff1a;將代碼編譯為ES5版本&#xff0c;確保更好的瀏覽器兼容性"module": "esnext…

第一節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門

Vben Admin vben5 系列文章目錄 &#x1f4bb; 基礎篇 ? 第一節&#xff1a;Vben Admin 最新 v5.0 (vben5) Python Flask 快速入門 ? 第二節&#xff1a;Vben Admin 最新 v5.0 (vben5) Python Flask 快速入門 - Python Flask 后端開發詳解(附源碼) ? 第三節&#xff1a;V…

Guava中常用的工具類

1. 集合工具類&#xff08;com.google.common.collect&#xff09;Guava 對 Java 集合框架進行了豐富擴展&#xff0c;解決了標準集合的諸多痛點。&#xff08;1&#xff09;Lists / Sets / Maps:用于簡化集合創建和操作&#xff1a;// 創建不可變集合&#xff08;線程安全&…

redission實現讀寫鎖的原理

Redisson 實現分布式讀寫鎖的核心原理是 ?基于 Redis 的 Lua 腳本原子操作? ?Pub/Sub 通知機制&#xff0c;在保證強一致性的同時實現高效的讀并發&#xff08;讀不阻塞讀&#xff0c;寫阻塞讀&#xff09;。以下是其核心設計&#xff1a;?一、核心數據結構?Redisson 使用…

【 ??SQL注入漏洞靶場】第二關文件讀寫

SQLi-Labs?它是一個開源的、專門為學習 ??Web安全?? 和 ??SQL注入技術?? 而設計的靶場項目。開發者故意在代碼中留下了各種不同類型的SQL注入漏洞&#xff0c;讓安全研究人員、學生和愛好者可以在一個合法、安全的環境中進行實戰練習&#xff0c;從而掌握發現和利用SQ…