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-appNginx 反向代理 + 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。