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
-
Install Vercel CLI:
npm install -g vercel -
Configure Project:
# From your project root vercel # Follow the prompts to link your project -
Add Environment Variables:
# Add each environment variable vercel env add NEXTAUTH_SECRET production vercel env add DATABASE_URL production # ... add all your environment variables -
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 deployRailway Deployment
Railway provides easy deployment with built-in PostgreSQL.
Setup Steps
-
Install Railway CLI:
npm install -g @railway/cli -
Login and Initialize:
railway login railway init -
Add PostgreSQL:
railway add postgresql -
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 -
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
-
Connect Repository:
- Go to Render Dashboard
- Click "New" → "Web Service"
- Connect your GitHub repository
-
Configure Build:
# Build Command pnpm install && pnpm build # Start Command pnpm start -
Add Environment Variables:
- Add all environment variables in Render dashboard
- Ensure
NODE_ENV=production
-
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: starterDocker 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:latestDocker 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:
-
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 -
Clone and Configure:
git clone your-repo supasecure cd supasecure cp .env.example .env.production # Edit .env.production with your values -
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 deployMigration Strategy
- Backup database before migrations
- Run migrations in maintenance window
- Test application after migration
- 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
-
Enable compression:
// next.config.ts const nextConfig = { compress: true, // ... other config } -
Optimize images:
// Use Next.js Image component import Image from 'next/image' <Image src="/logo.png" alt="Logo" width={200} height={100} priority /> -
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:
- Database migrations: Use reversible migrations
- Application code: Tag releases for easy rollback
- Environment variables: Keep backup of working config
- 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.