Documentation

Deployment Guide

Deploy your SAMS instance to production with various hosting providers.

Deployment Guide

This guide covers deploying SAMS to production using various hosting providers and deployment methods.

Prerequisites

Before deploying, ensure you have:

  • Working local development setup
  • Production database configured
  • Environment variables ready
  • OAuth providers configured for production
  • Email provider set up
  • Payment provider configured (if using billing)

Environment Configuration

Production Environment Variables

Create a production environment configuration:

# Database
DATABASE_URL="postgresql://user:pass@host:5432/dbname"

# Authentication
NEXTAUTH_SECRET="your-very-long-random-secret-key"
NEXTAUTH_URL="https://yourdomain.com"

# Application
NEXT_PUBLIC_APP_URL="https://yourdomain.com"
NEXT_PUBLIC_APP_NAME="Your App Name"

# Email
RESEND_API_KEY="re_your_production_api_key"
EMAIL_FROM="noreply@yourdomain.com"

# Payments
STRIPE_SECRET_KEY="sk_live_your_stripe_secret_key"
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_live_your_stripe_publishable_key"
STRIPE_WEBHOOK_SECRET="whsec_your_webhook_secret"

# OAuth Providers
GOOGLE_CLIENT_ID="your-production-google-client-id"
GOOGLE_CLIENT_SECRET="your-production-google-client-secret"
GITHUB_CLIENT_ID="your-production-github-client-id"
GITHUB_CLIENT_SECRET="your-production-github-client-secret"

Security Considerations

  • Never commit secrets to version control
  • Use strong random values for NEXTAUTH_SECRET
  • Enable HTTPS for all production deployments
  • Configure proper CORS settings
  • Set secure cookie flags in production

Vercel Deployment

Vercel is the easiest way to deploy SAMS.

Setup Steps

  1. Install Vercel CLI:

    npm install -g vercel
  2. Configure Project:

    # From your project root
    vercel
    
    # Follow the prompts to link your project
  3. Add Environment Variables:

    # Add each environment variable
    vercel env add NEXTAUTH_SECRET production
    vercel env add DATABASE_URL production
    # ... add all your environment variables
  4. Deploy:

    vercel --prod

Vercel Configuration

Create vercel.json in your project root:

{
  "framework": "nextjs",
  "buildCommand": "pnpm build",
  "installCommand": "pnpm install",
  "functions": {
    "apps/web/app/api/**/*.ts": {
      "maxDuration": 30
    }
  },
  "crons": [
    {
      "path": "/api/cron/cleanup",
      "schedule": "0 2 * * *"
    }
  ]
}

Database Migration

Run migrations after deployment:

# Run from packages/database
pnpm migrate deploy

Railway Deployment

Railway provides easy deployment with built-in PostgreSQL.

Setup Steps

  1. Install Railway CLI:

    npm install -g @railway/cli
  2. Login and Initialize:

    railway login
    railway init
  3. Add PostgreSQL:

    railway add postgresql
  4. Configure Environment:

    # Railway will automatically set DATABASE_URL
    # Add other environment variables
    railway variables set NEXTAUTH_SECRET=your-secret
    railway variables set NEXTAUTH_URL=https://your-app.railway.app
  5. Deploy:

    railway up

Railway Configuration

Create railway.toml:

[build]
builder = "nixpacks"
buildCommand = "pnpm build"

[deploy]
startCommand = "pnpm start"
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 10

[[services]]
name = "web"
source = "."

Render Deployment

Render provides a simple platform for full-stack applications.

Setup Steps

  1. Connect Repository:

    • Go to Render Dashboard
    • Click "New" → "Web Service"
    • Connect your GitHub repository
  2. Configure Build:

    # Build Command
    pnpm install && pnpm build
    
    # Start Command
    pnpm start
  3. Add Environment Variables:

    • Add all environment variables in Render dashboard
    • Ensure NODE_ENV=production
  4. Add PostgreSQL:

    • Create PostgreSQL service in Render
    • Connect to your web service

Render Configuration

Create render.yaml:

services:
  - type: web
    name: supasecure
    env: node
    plan: starter
    buildCommand: pnpm install && pnpm build
    startCommand: pnpm start
    envVars:
      - key: NODE_ENV
        value: production
      - key: NEXTAUTH_SECRET
        generateValue: true
      - key: DATABASE_URL
        fromDatabase:
          name: supasecure-db
          property: connectionString

databases:
  - name: supasecure-db
    plan: starter

Docker Deployment

Deploy using Docker for maximum control and portability.

Dockerfile

SAMS includes a production-ready Dockerfile:

FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install pnpm
RUN npm install -g pnpm

# Copy package files
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY packages packages
COPY apps/web/package.json ./apps/web/

# Install dependencies
RUN pnpm install --frozen-lockfile

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
RUN npm install -g pnpm

COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Build application
RUN pnpm build

# Production image
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# Copy built application
COPY --from=builder /app/apps/web/public ./apps/web/public
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000
ENV HOSTNAME "0.0.0.0"

CMD ["node", "apps/web/server.js"]

Build and Deploy

# Build image
docker build -t supasecure .

# Run locally
docker run -p 3000:3000 --env-file .env.local supasecure

# Deploy to registry
docker tag supasecure your-registry/supasecure:latest
docker push your-registry/supasecure:latest

Docker Compose

For development or self-hosting:

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/supasecure
      - NEXTAUTH_SECRET=your-secret
      - NEXTAUTH_URL=http://localhost:3000
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      - POSTGRES_DB=supasecure
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_data:

Self-Hosting

VPS Deployment

Deploy on your own VPS using Docker:

  1. Setup VPS:

    # Install Docker and Docker Compose
    curl -fsSL https://get.docker.com -o get-docker.sh
    sh get-docker.sh
    
    # Install Docker Compose
    sudo curl -L "https://github.com/docker/compose/releases/download/v2.0.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose
  2. Clone and Configure:

    git clone your-repo supasecure
    cd supasecure
    cp .env.example .env.production
    # Edit .env.production with your values
  3. Deploy:

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

Nginx Configuration

Set up Nginx as a reverse proxy:

server {
    server_name yourdomain.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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_cache_bypass $http_upgrade;
    }

    listen 443 ssl;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
}

Database Migration

Production Migration

Always run migrations before deploying application changes:

# From packages/database
pnpm migrate deploy

# Or using Docker
docker run --rm -e DATABASE_URL=$DATABASE_URL supasecure pnpm migrate deploy

Migration Strategy

  1. Backup database before migrations
  2. Run migrations in maintenance window
  3. Test application after migration
  4. Rollback plan if issues occur

Monitoring and Maintenance

Health Checks

Add health check endpoints:

// apps/web/app/api/health/route.ts
export async function GET() {
  try {
    // Check database connection
    await db.$queryRaw`SELECT 1`

    return Response.json({
      status: 'healthy',
      timestamp: new Date().toISOString()
    })
  } catch (error) {
    return Response.json(
      { status: 'unhealthy', error: error.message },
      { status: 503 }
    )
  }
}

Logging

Configure logging for production:

// lib/logger.ts
import winston from 'winston'

export const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' }),
  ],
})

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.simple()
  }))
}

Error Tracking

Integrate error tracking:

# Sentry
npm install @sentry/nextjs

# Configure in next.config.js
const { withSentryConfig } = require('@sentry/nextjs')

module.exports = withSentryConfig({
  // Your Next.js config
}, {
  // Sentry config
  silent: true,
  org: 'your-org',
  project: 'your-project',
})

Performance Optimization

Production Optimizations

  1. Enable compression:

    // next.config.ts
    const nextConfig = {
      compress: true,
      // ... other config
    }
  2. Optimize images:

    // Use Next.js Image component
    import Image from 'next/image'
    
    <Image
      src="/logo.png"
      alt="Logo"
      width={200}
      height={100}
      priority
    />
  3. Enable caching:

    // Add cache headers
    export async function GET() {
      return Response.json(data, {
        headers: {
          'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400'
        }
      })
    }

CDN Configuration

Use a CDN for static assets:

// next.config.ts
const nextConfig = {
  assetPrefix: process.env.NODE_ENV === 'production'
    ? 'https://cdn.yourdomain.com'
    : '',
}

Troubleshooting

Common Deployment Issues

Build Failures:

  • Check Node.js version compatibility
  • Verify all dependencies are installed
  • Check TypeScript errors
  • Ensure environment variables are set

Runtime Errors:

  • Check application logs
  • Verify database connection
  • Confirm all environment variables
  • Test health check endpoint

Performance Issues:

  • Enable monitoring and profiling
  • Check database query performance
  • Optimize bundle size
  • Use CDN for static assets

Rollback Strategy

Plan for rollbacks:

  1. Database migrations: Use reversible migrations
  2. Application code: Tag releases for easy rollback
  3. Environment variables: Keep backup of working config
  4. Monitoring: Set up alerts for issues

Congratulations! Your SAMS instance should now be running in production. Monitor your deployment and iterate based on user feedback and performance metrics.