404 Not Found

404 Not Found


nginx

Deploying Vercel + Docker

With MegaShop development complete, Charlie needs to deploy it to the production environment. Vercel offers a simple deployment process but has limited customization options, while Docker provides full control but involves complex configuration. Bob needs a deployment solution that's both flexible and reliable—using Vercel for the front end and API, and Docker for the database and Redis.

1. What You'll Learn


2. A True Story of an Architect

(1) Pain Point: Being able to run production environments locally

Charlie's MegaShop ran perfectly locally, but after deploying it to the server—environment variables were missing, the database couldn't be connected to, Redis wasn't running, and there were port conflicts. It took Bob five tries to successfully deploy it, and he ran into a different issue each time.

(2) The Docker + Vercel Solution

Docker packages the entire runtime environment, and Vercel deploys the frontend with zero configuration:

BASH
# Vercel: zero-config deploy
vercel --prod

# Docker: build once, run anywhere
docker compose up -d

(3) Benefits: One-click deployment + Consistent environments

Charlie uses git push to trigger Vercel deployment for the frontend and Docker Compose to manage the database, Redis, and Nuxt services, ensuring a completely consistent environment.


3. Deploying to Vercel

(1) Multi-platform Deployment of Decision Trees

100%
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]

(1) ▶ Example: Zero-Configuration Deployment on Vercel

BASH
# Install Vercel CLI
npm i -g vercel

# Deploy (auto-detects Nuxt 3)
vercel

# Production deploy
vercel --prod

Output:

TEXT
# Command executed successfully

(2) ▶ Example: nuxt.config.ts Vercel configuration

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
    }
  }
})

Output:

TEXT
// Execution Successful

(2) Pros and Cons of Vercel Deployment

Dimension Vercel Docker
Configuration Complexity 🟢 Zero configuration 🔴 Requires writing a Dockerfile
Deployment Speed ⚡ 30s 🟡 3-5 min build
Custom 🔴 Restricted 🟢 Full Control
Database 🔴 Requires an external service (Vercel Postgres) 🟢 Local deployment
Cost ⚠️ Billed per request 🟢 Fixed server fee
Extension 🟢 Automatic 🟡 Manual/K8s

4. Docker Deployment

(1) ▶ Example: Multi-stage 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"]

Output:

TEXT
// Execution Successful

(2) ▶ Example: Docker Compose Orchestration

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:

Output:

TEXT
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp

(3) ▶ Example: Nginx Reverse Proxy Configuration

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";
        }
    }
}

Output:

TEXT
// Execution Successful

5. Node.js Standalone + PM2

(1) ▶ Example: Building a Standalone Preset

TYPESCRIPT
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'node-server',
    compressPublicAssets: true
  }
})

Output:

TEXT
// Execution Successful
BASH
# Build standalone server
npm run build

# Output: .output/server/index.mjs
# Run directly
node .output/server/index.mjs

(2) ▶ Example: PM2 Process Management

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
  }]
}

Output:

TEXT
// Execution Successful
BASH
# Start with PM2
pm2 start ecosystem.config.js

# Monitor
pm2 monit

# Reload (zero-downtime)
pm2 reload megashop

# Logs
pm2 logs megashop

(1) Comparison of Deployment Options

Solution Complexity Manageability Scalability Applicability
Vercel 🟢 Low 🔴 Low 🟢 Automatic Small/Medium Teams
Docker Compose 🟡 Medium 🟢 High 🟡 Manual Medium/Large Teams
PM2 + Nginx 🟡 Medium 🟢 High 🟡 Manual VPS Deployment
K8s 🔴 High 🟢 Highest 🟢 Auto Large-scale

6. Comprehensive Example: MegaShop Production Deployment

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

❓ FAQ

Q Is Vercel's free tier sufficient?
A The free tier includes 100 GB of bandwidth per month and 1,000 hours of serverless usage. MegaShop's ISR cache hits for one million pages do not count toward function calls, so the free tier is sufficient for moderate traffic.
Q What are the benefits of Docker multi-stage builds?
A The final image contains only the files necessary for runtime and excludes source code and devDependencies. The image size is reduced from over 1 GB to approximately 150 MB, making it more secure and faster.
Q What is the difference between Nuxt standalone and the Node preset?
A There is no difference. The node-server preset generates standalone output (.output/server/index.mjs), does not require node_modules, and can be run directly.
Q Does PM2 cluster mode support SSR?
A Yes. Each worker is an independent process that renders SSR on its own. The ISR cache is shared via Redis and is accessible to all workers.
Q How do I run Prisma migrations in Docker?
A docker compose exec web npx prisma migrate deploy. Or add migration steps to your Dockerfile. For production, use migrate deploy (which does not create new migrations, but only applies existing ones).
Q How do I obtain an SSL certificate?
A For production environments, use Let's Encrypt + Certbot for automatic renewal. For Docker deployments, use nginx-proxy + acme-companion to automatically obtain one. Vercel includes SSL by default.

📖 Summary


📝 Exercises

  1. Basic Exercise (Difficulty: ⭐): Deploy MegaShop to Vercel, configure the environment variables, and verify that the SSR pages are working properly.
  2. Advanced Exercise (Difficulty: ⭐⭐): Write a Dockerfile and docker-compose.yml to launch the complete environment (Nuxt + PostgreSQL + Redis) locally.
  3. Challenge (Difficulty: ⭐⭐⭐): Implement a complete production deployment using Docker Compose, Nginx, and SSL, and configure health checks and automatic restarts.

---|

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏