Deployment Guide

Deploy your portfolio to production with confidence using this comprehensive deployment guide covering Vercel, Docker, and CI/CD pipelines.

Vercel offers the best experience for Next.js applications with zero configuration.

Initial Setup

  1. Install Vercel CLI
pnpm install -g vercel
  1. Login to Vercel
vercel login
  1. Link Project
vercel link

Follow the prompts to connect your project.

Deploy to Production

# Deploy to production
vercel --prod

# Deploy preview
vercel

Automatic Deployments

Connect your GitHub repository for automatic deployments:

  1. Go to vercel.com/dashboard
  2. Click "Add New Project"
  3. Import your GitHub repository
  4. Configure settings (usually auto-detected)
  5. Click "Deploy"

Automatic deployment triggers:

  • Production: Push to main branch
  • Preview: Pull requests and other branches

Environment Variables

Add environment variables in Vercel dashboard:

  1. Go to Project Settings > Environment Variables
  2. Add your variables:
NEXT_PUBLIC_GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=xxx
  1. Select environments (Production, Preview, Development)

Build Configuration

Vercel automatically detects Next.js projects. Custom settings in vercel.json:

{
  "buildCommand": "pnpm build",
  "devCommand": "pnpm dev",
  "installCommand": "pnpm install",
  "framework": "nextjs",
  "regions": ["iad1"],
  "env": {
    "NEXT_PUBLIC_APP_URL": "https://mohamedlakssirt.tech"
  }
}

Performance Optimizations

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "X-Content-Type-Options",
          "value": "nosniff"
        },
        {
          "key": "X-Frame-Options",
          "value": "DENY"
        },
        {
          "key": "X-XSS-Protection",
          "value": "1; mode=block"
        }
      ]
    }
  ],
  "rewrites": [
    {
      "source": "/api/:path*",
      "destination": "https://your-backend.com/api/:path*"
    }
  ]
}

🐳 Docker Deployment

For self-hosted or cloud deployments using Docker.

Production Dockerfile

Already included in the repository:

# Dockerfile
FROM node:20-alpine AS base

# Dependencies
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile

# Builder
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm build

# Runner
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs
EXPOSE 3000
ENV PORT 3000

CMD ["node", "server.js"]

Building Docker Image

# Build production image
docker build -t my-portfolio:latest .

# Build with build args
docker build \
  --build-arg NEXT_PUBLIC_GITHUB_TOKEN=ghp_xxx \
  -t my-portfolio:latest .

Running Docker Container

# Run container
docker run -d \
  --name portfolio \
  -p 3000:3000 \
  --env-file .env.production \
  --restart unless-stopped \
  my-portfolio:latest

# View logs
docker logs -f portfolio

# Stop container
docker stop portfolio

# Remove container
docker rm portfolio

Docker Compose Production

# docker-compose.prod.yml
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    env_file:
      - .env.production
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - app
    restart: unless-stopped

Deploy with:

docker-compose -f docker-compose.prod.yml up -d

Docker Wake-Up System

Smart container management for development/staging:

# Start wake-up system
./scripts/start-wake.sh

# Monitor locally
./scripts/start-wake.sh --monitor

Features:

  • Auto-starts container on first access
  • Stops after 30 minutes of inactivity
  • NGINX proxy shows loading page during startup
  • Monitors access and manages lifecycle

Configuration: docker-compose.yml

services:
  nginx-wake-proxy:
    image: nginx:alpine
    ports:
      - "3000:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app

  portfolio-app:
    build: .
    expose:
      - "3000"
    env_file:
      - .env.local

☁️ Cloud Providers

AWS Deployment

Using AWS Amplify

  1. Connect GitHub repository
  2. Configure build settings:
version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm install -g pnpm
        - pnpm install
    build:
      commands:
        - pnpm build
  artifacts:
    baseDirectory: .next
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*

Using ECS (Docker)

  1. Push image to ECR:
# Authenticate
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin xxx.dkr.ecr.us-east-1.amazonaws.com

# Tag image
docker tag my-portfolio:latest xxx.dkr.ecr.us-east-1.amazonaws.com/my-portfolio:latest

# Push
docker push xxx.dkr.ecr.us-east-1.amazonaws.com/my-portfolio:latest
  1. Create ECS task definition
  2. Configure service and load balancer

DigitalOcean App Platform

  1. Connect GitHub repository
  2. Configure in dashboard:
    • Build Command: pnpm build
    • Run Command: pnpm start
    • Environment: Node.js 20

Railway

# Install Railway CLI
npm install -g @railway/cli

# Login
railway login

# Initialize
railway init

# Deploy
railway up

🔄 CI/CD Pipeline

GitHub Actions

Automated testing and deployment workflow:

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '20'
      
      - name: Install pnpm
        run: npm install -g pnpm
      
      - name: Install dependencies
        run: pnpm install
      
      - name: Run linter
        run: pnpm lint
      
      - name: Run type check
        run: pnpm type-check
      
      - name: Run unit tests
        run: pnpm test:unit
      
      - name: Run E2E tests
        run: pnpm test:e2e:ci
  
  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '20'
      
      - name: Install pnpm
        run: npm install -g pnpm
      
      - name: Install dependencies
        run: pnpm install
      
      - name: Build
        run: pnpm build
        env:
          NEXT_PUBLIC_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  
  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

Deployment Checklist

Before deploying to production:

  • Run full test suite: pnpm validate
  • Check for security vulnerabilities: pnpm audit
  • Update environment variables
  • Test build locally: pnpm build && pnpm start
  • Verify all API endpoints work
  • Check responsive design on all devices
  • Test light/dark mode switching
  • Verify GitHub stats loading
  • Check Core Web Vitals scores
  • Review Lighthouse report
  • Test in multiple browsers
  • Update CHANGELOG.md
  • Create git tag for release

Post-Deployment

After successful deployment:

  1. Verify Deployment

    • Check production URL loads correctly
    • Test all major features
    • Verify analytics tracking
  2. Monitor Performance

    • Check Vercel Analytics dashboard
    • Review error logs
    • Monitor Core Web Vitals
  3. Update Documentation

    • Document any configuration changes
    • Update README if needed
    • Record deployment notes

🔐 Security Best Practices

Environment Variables

  • Never commit .env.local to git
  • Use different tokens for dev/prod
  • Rotate tokens regularly
  • Use secret management services

Headers

Add security headers in next.config.ts:

const nextConfig = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'X-DNS-Prefetch-Control',
            value: 'on'
          },
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=63072000; includeSubDomains; preload'
          },
          {
            key: 'X-Content-Type-Options',
            value: 'nosniff'
          },
          {
            key: 'X-Frame-Options',
            value: 'SAMEORIGIN'
          },
          {
            key: 'Referrer-Policy',
            value: 'origin-when-cross-origin'
          }
        ]
      }
    ];
  }
};

SSL/TLS

  • Always use HTTPS in production
  • Configure automatic certificate renewal
  • Use tools like Let's Encrypt for free certificates

📊 Monitoring

Vercel Analytics

Built-in analytics for:

  • Core Web Vitals
  • Page load times
  • Error tracking
  • User sessions

PostHog

Product analytics for:

  • User behavior
  • Feature usage
  • Conversion funnels
  • A/B testing

Error Tracking

Consider adding:

  • Sentry for error monitoring
  • LogRocket for session replay
  • Datadog for infrastructure monitoring

📚 Learn More

On this page