三种部署形态
| 形态 | 适用 |
|---|---|
| 托管平台(Vercel / Netlify / Cloudflare Pages) | 80% 项目首选 |
| 自建 VPS | 已有服务器、要省钱、要数据可控 |
| K8s / 容器编排 | 大团队、多服务、企业级 |
react-quick/16 讲了 Vercel;react-quick/17 讲了 VPS。这篇补生产级清单——不论部署在哪都该做的事。
1. 环境变量
# .env.local 不进 git
DATABASE_URL=postgres://...
JWT_SECRET=...
# .env.example 进 git(占位)
DATABASE_URL=
JWT_SECRET=
NEXT_PUBLIC_* 前缀的会编译进客户端 bundle——只放可公开的值(如 GA ID、地图 key)。
.env.production 在 CI / 部署平台配,本地不存。
2. 构建 + 启动
npm ci # 严格按 lock 装,不更新
npm run build # 出 .next/
NODE_ENV=production npm start # 或 next start
Docker 化(K8s / 自建都用):
# Dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-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"]
next.config.js:
module.exports = { output: 'standalone' }; // 启用 standalone bundle
镜像只带运行所需,体积小一半。
3. 进程管理
VPS 上推荐两种:
systemd(用 PM2 也行):
# /etc/systemd/system/myapp.service
[Unit]
Description=My Next.js
After=network.target
[Service]
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node server.js
Restart=on-failure
Environment="NODE_ENV=production"
Environment="PORT=3000"
User=www
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
systemctl enable --now myapp
journalctl -u myapp -f # 看日志
4. 反向代理(Nginx)
upstream nextapp { server 127.0.0.1:3000; keepalive 64; }
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# gzip / br
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
# 静态资产缓存 1 年
location /_next/static/ {
proxy_pass http://nextapp;
add_header Cache-Control "public, max-age=31536000, immutable";
}
location / {
proxy_pass http://nextapp;
proxy_http_version 1.1;
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_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
5. HTTPS
Let's Encrypt + certbot 全套:
sudo dnf install epel-release # CentOS / Rocky
sudo dnf install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
sudo systemctl enable --now certbot-renew.timer
证书 90 天自动续。别忘了重定向 HTTP→HTTPS、加 HSTS:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
6. 监控
最低三件套:
1. 运行状态:UptimeRobot / Better Stack / Pingdom——免费层够个人用。
GET https://example.com/api/health → 200 才算活
实现一个健康检查:
// app/api/health/route.ts
export async function GET() {
// 真正测一下能不能查库 / 关键依赖
const dbOk = await db.$queryRaw`SELECT 1`.then(() => true).catch(() => false);
return Response.json({ ok: dbOk }, { status: dbOk ? 200 : 503 });
}
2. 错误追踪:Sentry(自托管也行)
npx @sentry/wizard@latest -i nextjs
自动捕获前端 + 后端错误、source map 上传、user feedback。
3. 性能 / Web Vitals:
// app/web-vitals.ts
'use client';
import { useReportWebVitals } from 'next/web-vitals';
export function WebVitals() {
useReportWebVitals((m) => {
fetch('/api/vitals', { method: 'POST', body: JSON.stringify(m) });
});
}
也可以接 Vercel Analytics / Plausible / 自建。
7. 日志
结构化日志:JSON 输出,方便采集
import pino from 'pino';
const log = pino({ level: 'info' });
log.info({ userId, action: 'login' }, 'user logged in');
journalctl / Loki / Datadog 都能解析 JSON。
8. 备份
- 数据库:每日全量 + WAL 增量;备份到异地(不同 region 的对象存储)
- 用户上传:S3 / OSS / R2 自带跨区域复制
- 演练:每季度真的恢复一次——光备份没演练等于没备份
9. CI/CD
# .github/workflows/deploy.yml
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm run lint
- run: npm run test -- --run
- run: npm run build
- name: Deploy
run: |
rsync -avz --delete .next/standalone/ user@server:/var/www/myapp/
ssh user@server 'sudo systemctl restart myapp'
或者直接用 Vercel / Netlify 的内置部署(push 即上线)。
10. 安全清单
- 所有 secret 在环境变量,不进代码
-
npm audit在 CI 跑,高危依赖阻断 - 请求 rate limit(Vercel KV / Upstash 都有现成)
- CSP 头:
default-src 'self' - CSRF:Server Actions 自带,自己写的 API 别忘
- Auth 用 Auth.js / Clerk / Lucia,不要自己手写
- 数据库连接最小权限(不要用 admin 跑应用)
11. 回滚预案
永远要能 30 秒内回滚:
- Vercel:上一个 deployment 一键 promote
- 自建:保留上一版本镜像 / 文件,systemd unit 切换 + 重启
- 数据库 schema 变更必须前向兼容(先改 schema 再改代码,不要反过来)
上线前自检清单
- HTTPS 证书有效 + 自动续签
- 健康检查 endpoint 配在监控
- 错误追踪接通(故意触发一次确认收到)
- 日志能在主机外看到
- 数据库定时备份 + 至少手动恢复过一次
- CI 跑通 lint + test + build
- 域名 DNS 正确(A / AAAA / CNAME)
- 文件上传大小、并发请求限流配好
- 隐私政策 / Cookie 同意(如需)
- sitemap.xml + robots.txt
→ 最后一篇 继续往哪走