Nuxt: 部署 Vercel + Docker
最后更新:2026-08-26
MegaShop 开发完成,Charlie 要部署到生产环境。Vercel 部署简单但定制性有限,Docker 可以完全控制但配置复杂。Bob 需要一个既灵活又可靠的部署方案——Vercel 给前端 + API,Docker 给数据库和 Redis。
1. 你将学到
- Vercel 部署:零配置 + Nitro preset + 环境变量
- Docker 部署:Dockerfile + 多阶段构建 + docker-compose
- Node.js 部署:standalone preset + PM2
- 静态托管:Cloudflare Pages / Netlify / S3
- MegaShop 生产部署实战:Vercel + Docker Compose
2. 一个架构师的真实故事
(1) 痛点:本地能跑生产挂
Charlie 的 MegaShop 本地运行完美,但部署到服务器后——环境变量缺失、数据库连不上、Redis 未启动、端口冲突。Bob 试了 5 次才部署成功,每次都踩不同的坑。
(2) Docker + Vercel 的解法
Docker 打包整个运行环境,Vercel 零配置部署前端:
BASH
# Vercel: zero-config deploy
vercel --prod
# Docker: build once, run anywhere
docker compose up -d
(3) 收益:一键部署 + 环境一致
Charlie 用 git push 触发 Vercel 部署前端,Docker Compose 管理数据库/Redis/Nuxt 服务,环境完全一致。
3. Vercel 部署
(1) 多平台部署决策树
flowchart TB
A[Deploy Nuxt 3 App] --> B{Need SSR?}
B -->|No| C[Static Hosting<br/>Cloudflare/Netlify/S3]
B -->|Yes| D{Team size?}
D -->|Small/Medium| E[Vercel<br/>Zero-config deploy]
D -->|Large/Enterprise| F[Docker + Node.js<br/>Full control]
E --> G[API + Frontend on Vercel]
F --> H[Docker Compose<br/>Nuxt + PostgreSQL + Redis]
▶ 示例:Vercel 零配置部署
BASH
# Install Vercel CLI
npm i -g vercel
# Deploy (auto-detects Nuxt 3)
vercel
# Production deploy
vercel --prod
输出:
TEXT
📖 仅展示
# 命令执行成功
▶ 示例:nuxt.config.ts Vercel 配置
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'vercel' // Auto-configured by Vercel
},
// Environment variables set in Vercel dashboard
runtimeConfig: {
databaseUrl: process.env.DATABASE_URL,
redisUrl: process.env.REDIS_URL,
public: {
apiBase: process.env.API_BASE
}
}
})
输出:
TEXT
📖 仅展示
// 执行成功
(2) Vercel 部署优缺点
| 维度 | Vercel | Docker |
|---|---|---|
| 配置复杂度 | 🟢 零配置 | 🔴 需写 Dockerfile |
| 部署速度 | ⚡ 30s | 🟡 3-5min build |
| 自定义 | 🔴 受限 | 🟢 完全控制 |
| 数据库 | 🔴 需外部(Vercel Postgres) | 🟢 本地部署 |
| 成本 | ⚠️ 按请求计费 | 🟢 固定服务器费用 |
| 扩展 | 🟢 自动 | 🟡 手动/K8s |
4. Docker 部署
▶ 示例:多阶段 Dockerfile
DOCKERFILE
# Dockerfile
# Stage 1: Install dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npx prisma generate
RUN npm run build
# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Copy built assets
COPY --from=builder /app/.output ./.output
COPY --from=builder /app/prisma ./prisma
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]
输出:
TEXT
📖 仅展示
// 执行成功
▶ 示例:Docker Compose 编排
YAML
# docker-compose.yml
version: '3.8'
services:
# Nuxt application
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://megashop:megashop_pass@db:5432/megashop
- REDIS_URL=redis://redis:6379
- JWT_ACCESS_SECRET=${JWT_ACCESS_SECRET}
- JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET}
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
# PostgreSQL database
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=megashop
- POSTGRES_PASSWORD=megashop_pass
- POSTGRES_DB=megashop
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U megashop"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
# Redis cache
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped
# Nginx reverse proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- web
restart: unless-stopped
volumes:
postgres_data:
redis_data:
输出:
TEXT
📖 仅展示
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
▶ 示例:Nginx 反向代理配置
NGINX
# nginx.conf
events {
worker_connections 1024;
}
http {
upstream nuxt {
server web:3000;
}
server {
listen 80;
server_name megashop.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name megashop.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location / {
proxy_pass http://nuxt;
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;
}
# Cache static assets
location /_nuxt/ {
proxy_pass http://nuxt;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
输出:
TEXT
📖 仅展示
// 执行成功
5. Node.js Standalone + PM2
▶ 示例:Standalone 预设构建
TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'node-server',
compressPublicAssets: true
}
})
输出:
TEXT
📖 仅展示
// 执行成功
BASH
# Build standalone server
npm run build
# Output: .output/server/index.mjs
# Run directly
node .output/server/index.mjs
▶ 示例:PM2 进程管理
JAVASCRIPT
// ecosystem.config.js
module.exports = {
apps: [{
name: 'megashop',
script: '.output/server/index.mjs',
instances: 'max', // Use all CPU cores
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000,
DATABASE_URL: 'postgresql://megashop:pass@localhost:5432/megashop',
REDIS_URL: 'redis://localhost:6379'
},
max_memory_restart: '1G',
error_file: './logs/error.log',
out_file: './logs/out.log',
merge_logs: true,
autorestart: true
}]
}
输出:
TEXT
📖 仅展示
// 执行成功
BASH
# Start with PM2
pm2 start ecosystem.config.js
# Monitor
pm2 monit
# Reload (zero-downtime)
pm2 reload megashop
# Logs
pm2 logs megashop
(1) 部署方案对比
| 方案 | 复杂度 | 可控性 | 扩展性 | 适用 |
|---|---|---|---|---|
| Vercel | 🟢 低 | 🔴 低 | 🟢 自动 | 小/中团队 |
| Docker Compose | 🟡 中 | 🟢 高 | 🟡 手动 | 中/大团队 |
| PM2 + Nginx | 🟡 中 | 🟢 高 | 🟡 手动 | VPS 部署 |
| K8s | 🔴 高 | 🟢 最高 | 🟢 自动 | 大规模 |
6. 综合示例:MegaShop 生产部署
BASH
# ============================================
# MegaShop Production Deployment
# Docker Compose + Nginx + PostgreSQL + Redis
# ============================================
# 1. Clone and configure
git clone https://github.com/megashop/megashop.git
cd megashop
cp .env.example .env
# Edit .env with production secrets
# 2. Build and start
docker compose up -d --build
# 3. Run database migrations
docker compose exec web npx prisma migrate deploy
# 4. Seed initial data (first time only)
docker compose exec web npx prisma db seed
# 5. Verify
curl https://megashop.com/api/products?limit=5
# 6. Monitor
docker compose logs -f web
❓ 常见问题
Q Vercel 免费额度够用吗?
A 免费版 100GB 带宽/月 + Serverless 1000 小时。MegaShop 百万页 ISR 命中缓存不计 Function 调用,免费版够中等流量。
Q Docker 多阶段构建有什么好处?
A 最终镜像只包含运行时必要文件,不含源码和 devDependencies。镜像从 1GB+ 缩小到 ~150MB,更安全更快。
Q Nuxt standalone 和 Node preset 有什么区别?
A 没有区别。
node-server preset 生成 standalone 输出(.output/server/index.mjs),不需要 node_modules,可直接运行。Q PM2 cluster 模式支持 SSR 吗?
A 支持。每个 worker 是独立进程,各自渲染 SSR。ISR 缓存用 Redis 共享,所有 worker 共用。
Q Docker 里怎么运行 Prisma 迁移?
A
docker compose exec web npx prisma migrate deploy。或在 Dockerfile 里添加迁移步骤。生产用 migrate deploy(不创建新迁移,只应用已有的)。Q SSL 证书怎么获取?
A 生产环境用 Let's Encrypt + Certbot 自动续期。Docker 部署可用 nginx-proxy + acme-companion 自动获取。Vercel 自带 SSL。
📖 小节
- Vercel 零配置部署,适合小/中团队,API + 前端一体
- Docker 多阶段构建生成精简镜像,Docker Compose 编排全套服务
- PM2 cluster 模式实现多进程 + 零停机重载
- Nginx 反向代理 + SSL + 静态资源缓存
- MegaShop 推荐 Docker Compose:Nuxt + PostgreSQL + Redis + Nginx
📝 作业
- 基础题(难度⭐):将 MegaShop 部署到 Vercel,配置环境变量,验证 SSR 页面正常
- 进阶题(难度⭐⭐):编写 Dockerfile + docker-compose.yml,本地启动完整环境(Nuxt + PostgreSQL + Redis)
- 挑战题(难度⭐⭐⭐):实现 Docker Compose + Nginx + SSL 的完整生产部署,配置健康检查和自动重启
---|