Next.js 是目前最流行的 React 服务端渲染框架,支持 SSR、SSG、API Routes 等特性。将 Next.js 应用部署到搬瓦工 VPS,可以完全自主控制服务器环境、域名和性能配置。本文介绍两种主流方案:PM2 守护独立模式输出,以及 Docker 容器化部署,并配置 Nginx 反代与 SSL。

本文要点

  • 构建 Next.js 生产包(standalone 模式)
  • PM2 守护 Next.js 进程与开机自启
  • Nginx 反向代理 + Let's Encrypt SSL
  • Docker 多阶段构建与容器化部署

准备:构建 Next.js 应用

在本地或 VPS 上构建生产包。推荐开启 standalone 输出模式,大幅减少部署体积:

next.config.js 中添加:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: "standalone",
};
module.exports = nextConfig;
# 安装依赖并构建
npm ci
npm run build

# standalone 输出位于 .next/standalone/
# 静态资源位于 .next/static/

方案一:PM2 守护(推荐)

构建完成后,将以下文件部署到服务器:

  • .next/standalone/(含服务端代码与 server.js)
  • .next/static/(复制到 .next/standalone/.next/static/
  • public/(复制到 .next/standalone/public/
# 在 VPS 上整理目录结构
mkdir -p /opt/myapp
# 传输后执行
cp -r .next/static .next/standalone/.next/static
cp -r public .next/standalone/public

# 用 PM2 启动
pm2 start .next/standalone/server.js \
  --name nextjs-app \
  --cwd /opt/myapp/.next/standalone
pm2 save

创建 ecosystem.config.js 方便管理:

module.exports = {
  apps: [{
    name: "nextjs-app",
    script: ".next/standalone/server.js",
    cwd: "/opt/myapp",
    env_production: {
      NODE_ENV: "production",
      PORT: 3000,
      HOSTNAME: "127.0.0.1",
    },
  }],
};

方案二:Docker 多阶段构建

创建 Dockerfile

FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
docker build -t nextjs-app .
docker run -d \
  --name nextjs-app \
  -p 3000:3000 \
  -e NODE_ENV=production \
  --restart unless-stopped \
  nextjs-app

Nginx 反向代理 + SSL

申请证书后创建 /etc/nginx/conf.d/nextjs.conf

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    server_name yourdomain.com www.yourdomain.com;
    ssl_certificate     /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    # 静态资源缓存
    location /_next/static/ {
        alias /opt/myapp/.next/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
    }
}
部署方式优点适合场景
PM2 standalone部署轻量、调试方便个人项目、快速上线
Docker 容器环境隔离、可复现团队协作、多项目共存

SSL 自动续签

certbot 会自动在 /etc/cron.d/ 添加续签任务,证书到期前自动更新,无需手动操作。执行 certbot renew --dry-run 可提前验证续签配置是否正常。

小结

  • standalone 模式显著缩减部署体积,是生产部署的推荐配置
  • PM2 方案轻量适合快速上线,Docker 方案环境隔离适合团队
  • Nginx 反代负责 SSL 终止和静态资源缓存
  • 静态资源设置长期缓存可大幅提升加载速度

常见问题

Next.js 不用 standalone 模式可以部署吗?

可以,直接用 pm2 start node_modules/.bin/next --name app -- start 启动即可,但 node_modules 完整上传体积较大,standalone 更适合 VPS 部署。

部署后图片显示不出来怎么办?

检查 public/ 目录是否已复制到 standalone 目录,以及 next.config.js 中的 images.domains 是否包含外部图片域名。

如何实现零停机更新代码?

重新构建后替换文件,然后执行 pm2 reload nextjs-app。如果用 Docker,则重新构建镜像并执行 docker compose up -d。