Nuxt CI/CD 部署
记录 Nuxt 应用的自动化部署流程,包括 GitHub Actions 配置、PM2 进程管理、环境变量安全等内容。
概述
CI/CD(持续集成/持续部署)是现代 Web 开发的标准实践。对于 Nuxt 应用而言,由于涉及服务端渲染、预渲染、环境变量等多个环节,部署流程相对复杂。本文记录了 Nuxt 应用的 CI/CD 部署实践。
部署架构
流程概览
开发者推送代码到 GitHub
│
▼
┌─────────────────────────────┐
│ GitHub Actions 触发 │
│ ┌─────────────────────────┐│
│ │ 1. Checkout 代码 ││
│ │ 2. Setup Node.js ││
│ │ 3. npm ci ││
│ │ 4. 构建项目 ││
│ │ 5. 打包构建产物 ││
│ └─────────────────────────┘│
└─────────────────────────────┘
│
▼
┌─────────────────────────────┐
│ SCP 上传到服务器 │
└─────────────────────────────┘
│
▼
┌─────────────────────────────┐
│ SSH 远程执行部署 │
│ ┌─────────────────────────┐│
│ │ 1. 清理旧构建产物 ││
│ │ 2. 解压新构建产物 ││
│ │ 3. PM2 重启服务 ││
│ └─────────────────────────┘│
└─────────────────────────────┘
│
▼
部署完成服务器架构
┌─────────────┐
用户请求 ──────►│ Nginx │
│ (端口 80) │
└──────┬──────┘
│ 反向代理
▼
┌─────────────┐
│ Nuxt │
│ (端口 3000)│
│ PM2 集群 │
└─────────────┘GitHub Actions 配置
官方文档:https://docs.github.com/en/actions
工作流文件
创建 .github/workflows/deploy.yml:
name: Deploy
on:
push:
branches:
- main
workflow_dispatch: # 支持手动触发
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. 检出代码
- name: Checkout
uses: actions/checkout@v4
# 2. 设置 Node.js 环境
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
# 3. 安装依赖
- name: Install dependencies
run: |
npm ci
npm install --platform=linux --arch=x64 sharp
# 4. 安装 jemalloc(可选,解决 sharp 内存问题)
- name: Install jemalloc
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq libjemalloc2 > /dev/null 2>&1
# 5. 构建项目
- name: Build Project
run: npm run build
env:
NODE_ENV: production
NODE_OPTIONS: '--max-old-space-size=6144 --no-node-snapshot'
VIPS_WARNING: '0'
LD_PRELOAD: /usr/lib/x86_64-linux-gnu/libjemalloc.so.2
# 6. 打包构建产物
- name: Zip Output
run: tar -czf release.tar.gz .output ecosystem.config.cjs
# 7. 上传到服务器
- name: Upload to Server
uses: appleboy/scp-action@v0.1.4
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
source: 'release.tar.gz'
target: '/tmp'
# 8. 执行部署
- name: Execute Deploy
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /opt/app
rm -rf .output
tar -xzf /tmp/release.tar.gz -C /opt/app
rm /tmp/release.tar.gz
pm2 delete app 2>/dev/null || true
if [ -f /opt/app/.env ]; then
set -a; source /opt/app/.env; set +a
fi
pm2 start ecosystem.config.cjs
pm2 save关键配置说明
跨平台依赖安装
- name: Install dependencies
run: |
npm ci
npm install --platform=linux --arch=x64 sharpCI 环境是 Linux,但开发环境可能是 Windows/macOS。npm ci 会根据当前平台安装依赖,需要额外安装 Linux 平台的 sharp 原生二进制。
内存优化
NODE_OPTIONS: '--max-old-space-size=6144 --no-node-snapshot'--max-old-space-size=6144:将 Node.js 堆内存上限设为 6GB--no-node-snapshot:禁用 V8 快照,减少内存占用
jemalloc
sharp 依赖的 libvips 在某些环境下可能与 glibc 默认的内存分配器冲突,导致 munmap_chunk(): invalid pointer 崩溃。使用 jemalloc 可以解决这个问题:
LD_PRELOAD: /usr/lib/x86_64-linux-gnu/libjemalloc.so.2GitHub Secrets 配置
必需的 Secrets
在 GitHub 仓库的 Settings → Secrets and variables → Actions 中配置:
| Secret 名称 | 说明 |
|---|---|
SERVER_HOST | 服务器 IP 地址 |
SERVER_USER | SSH 登录用户名 |
SERVER_SSH_KEY | SSH 私钥完整内容 |
STUDIO_GITHUB_CLIENT_ID | GitHub OAuth Client ID(如使用 Nuxt Studio) |
STUDIO_GITHUB_CLIENT_SECRET | GitHub OAuth Client Secret |
SSH 密钥配置
- 生成 SSH 密钥对:
ssh-keygen -t ed25519 -C "github-actions" -f github-actions- 将公钥添加到服务器:
ssh-copy-id -i github-actions.pub user@your-server- 将私钥内容添加到 GitHub Secrets 的
SERVER_SSH_KEY。
GitHub OAuth App 配置
如需使用 Nuxt Studio,需要配置 GitHub OAuth:
- 前往 GitHub Developer Settings → OAuth Apps → New OAuth App
填写信息:
- Homepage URL:
https://your-domain.com - Authorization callback URL:
https://your-domain.com/__nuxt_studio/auth/github
- Homepage URL:
- 创建后获取 Client ID 和 Client Secret
PM2 配置
官方文档:https://pm2.keymetrics.io
ecosystem.config.cjs
module.exports = {
apps: [
{
name: 'app',
port: '3000',
exec_mode: 'cluster',
instances: 'max',
script: './.output/server/index.mjs',
max_memory_restart: '512M',
env: {
NODE_ENV: 'production',
NITRO_PRESET: 'node-server',
NUXT_PUBLIC_SITE_URL: 'https://example.com'
}
}
]
}配置项说明
| 配置项 | 值 | 说明 |
|---|---|---|
exec_mode | cluster | 集群模式,利用多核 CPU |
instances | max | 启动与 CPU 核心数相同的进程 |
max_memory_restart | 512M | 单进程内存超限自动重启 |
script | .output/server/index.mjs | Nuxt 服务端入口 |
环境变量注意事项
运行时不要设置 NUXT_STUDIO 环境变量。Nuxt 会将所有 NUXT_ 前缀的环境变量映射到 runtimeConfig。如果设置 NUXT_STUDIO='true',会把 runtimeConfig.studio 从对象覆盖为字符串,导致运行时报错。
NUXT_STUDIO 仅在构建时用于条件判断是否加载 nuxt-studio 模块。
服务器环境配置
目录结构
/opt/app/
├── .output/ # Nuxt 构建产物(CI 部署时覆盖)
│ └── server/
│ └── index.mjs # 服务端入口
├── ecosystem.config.cjs # PM2 配置(CI 部署时覆盖)
└── .env # 运行时凭据(手动创建,不被覆盖)服务器 .env 文件
# /opt/app/.env
# Nuxt Studio GitHub OAuth(如使用)
STUDIO_GITHUB_CLIENT_ID=your_client_id
STUDIO_GITHUB_CLIENT_SECRET=your_client_secret
STUDIO_GITHUB_REDIRECT_URL=https://example.com/__nuxt_studio/auth/github.env 文件不会被 CI 部署覆盖,首次部署时需要手动创建。
Node.js 环境安装
推荐使用 nvm 管理 Node.js 版本:
# 安装 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
# 安装 Node.js 22
nvm install 22
nvm use 22
nvm alias default 22
# 安装 PM2
npm install -g pm2PM2 常用命令
# 启动服务
pm2 start ecosystem.config.cjs
# 查看状态
pm2 status
# 查看日志
pm2 logs app
# 实时监控
pm2 monit
# 重启服务
pm2 restart app
# 停止服务
pm2 stop app
# 保存当前进程列表(开机自启)
pm2 save
# 生成开机自启脚本
pm2 startupNginx 配置
反向代理配置
# /etc/nginx/sites-available/app
server {
listen 80;
server_name example.com www.example.com;
# 重定向到 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL 证书
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# 反向代理到 Nuxt
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
# 静态资源缓存
location /_nuxt/ {
proxy_pass http://localhost:3000;
proxy_cache static_cache;
proxy_cache_valid 200 365d;
proxy_cache_key $uri;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# IPX 图片缓存
location /_ipx/ {
proxy_pass http://localhost:3000;
proxy_cache image_cache;
proxy_cache_valid 200 7d;
add_header Cache-Control "public, max-age=604800";
}
}启用配置
# 创建软链接
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
# 测试配置
sudo nginx -t
# 重载 Nginx
sudo systemctl reload nginxNginx 官方文档:https://nginx.org/en/docs
环境变量管理
构建时 vs 运行时
| 阶段 | 变量来源 | 用途 |
|---|---|---|
| 构建时 | GitHub Actions env 块 | 条件加载模块、注入凭据 |
| 运行时 | 服务器 .env 文件 | OAuth 认证、API 密钥 |
环境变量前缀约定
| 前缀 | 处理方式 | 示例 |
|---|---|---|
NUXT_ | 自动映射到 runtimeConfig | NUXT_PUBLIC_SITE_URL |
STUDIO_ | nuxt-studio 模块直接读取 | STUDIO_GITHUB_CLIENT_ID |
NITRO_ | Nitro 引擎配置 | NITRO_PRESET |
安全建议
- 敏感信息不入库:OAuth 凭据、API 密钥等通过 Secrets 或
.env管理 - 最小权限原则:OAuth App 只请求必要的 scope
- 定期轮换:定期更新密钥和令牌
- 审计日志:监控异常登录和操作
故障排查
构建失败:OOM
症状:JavaScript heap out of memory
解决:增加 Node.js 堆内存
NODE_OPTIONS: '--max-old-space-size=6144'构建失败:munmap_chunk
症状:munmap_chunk(): invalid pointer
解决:安装并使用 jemalloc
- name: Install jemalloc
run: sudo apt-get install -y libjemalloc2
- name: Build Project
env:
LD_PRELOAD: /usr/lib/x86_64-linux-gnu/libjemalloc.so.2PM2 进程异常重启
排查命令:
# 查看进程状态
pm2 status
# 查看日志
pm2 logs app --lines 100
# 查看内存使用
pm2 monit如果频繁因内存超限重启,调整 max_memory_restart 值。
部署后页面 404
排查步骤:
- 确认
.output/目录已正确解压 - 确认 PM2 进程正在运行
- 检查 Nginx 配置是否正确
高级配置
多环境部署
# .github/workflows/deploy.yml
jobs:
deploy-staging:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
environment: staging
steps:
# ... 部署到测试环境
deploy-production:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment: production
steps:
# ... 部署到生产环境部署通知
- name: Notify on Success
if: success()
uses: 8398a7/action-slack@v3
with:
status: success
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
- name: Notify on Failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
webhook_url: ${{ secrets.SLACK_WEBHOOK }}部署检查清单
首次部署
- 服务器安装 Node.js 22+
- 服务器安装 PM2
- 配置 GitHub Secrets
- 创建服务器
.env文件 - 配置 Nginx 反向代理
- 配置 SSL 证书
- 设置 PM2 开机自启
每次部署
- 检查 GitHub Actions 日志
- 验证网站可访问
- 检查 PM2 进程状态
- 查看应用日志
定期维护
- 更新依赖版本
- 轮换 OAuth 凭据
- 检查 SSL 证书有效期
- 清理旧日志和备份
小结
Nuxt 应用的 CI/CD 部署涉及多个环节。GitHub Actions 实现自动化构建和部署流程,PM2 提供进程管理和集群模式,Nginx 处理反向代理和静态资源缓存。环境变量需要在构建时和运行时分别管理,确保敏感信息安全。遇到问题时,可以通过日志和监控工具进行排查。
参考资料:
- 上一篇:Nuxt 4 核心特性与开发实践
- 下一篇:EdgeOne相关配置