Skip to main content

Overview

This guide covers deploying Tambo360 to production, including platform-specific instructions, database setup, environment configuration, and best practices for a secure and scalable deployment.
Always test your deployment in a staging environment before deploying to production.

Pre-Deployment Checklist

Before deploying to production, ensure you have:
1

Environment Configuration

  • Production environment variables configured
  • Strong JWT_SECRET generated (min 32 characters)
  • Database credentials secured
  • Email service configured (SendGrid/Gmail)
  • CORS origins properly restricted
2

Database Setup

  • Production PostgreSQL database provisioned
  • Database backups configured
  • Connection pooling enabled
  • SSL/TLS connections enabled
  • Migrations tested in staging
3

Security

  • All secrets stored securely (not in code)
  • HTTPS enabled for frontend and backend
  • Security headers configured
  • Rate limiting implemented
  • Input validation enabled
4

Testing

  • All tests passing
  • Load testing completed
  • Security audit performed
  • Backup/restore tested

Deployment Architecture

Platform Options

Docker

Self-hosted with full control

Railway

Easy deployment with PostgreSQL

Render

Automatic deploys from GitHub

AWS

Scalable cloud infrastructure

DigitalOcean

Droplets with App Platform

Vercel + Railway

Frontend on Vercel, Backend on Railway

Docker Production Deployment

Build Production Images

1

Prepare environment

Create production environment file:
.env.production
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://user:password@db-host:5432/tambo?sslmode=require
JWT_SECRET=your-production-secret-min-32-chars
FRONTEND_URL=https://app.tambo360.com
BACKEND_URL=https://api.tambo360.com
EMAIL_USER=[email protected]
SENDGRID_API_KEY=SG.xxxxxxxxxxxxx
2

Build backend image

cd apps/backend
docker build --target production -t tambo360-backend:latest .
3

Build frontend image

cd apps/frontend
docker build --target production -t tambo360-frontend:latest .
4

Run production stack

# Using docker-compose
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
5

Run database migrations

docker compose exec backend npx prisma migrate deploy

Production Docker Compose

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

services:
  backend:
    build:
      context: ./apps/backend
      target: production
    restart: always
    environment:
      - NODE_ENV=production
      - DATABASE_URL=${DATABASE_URL}
      - JWT_SECRET=${JWT_SECRET}
    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  frontend:
    build:
      context: ./apps/frontend
      target: production
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      backend:
        condition: service_healthy

Railway Deployment

Railway provides easy deployment with built-in PostgreSQL.
1

Install Railway CLI

npm install -g @railway/cli
railway login
2

Create new project

railway init
3

Add PostgreSQL database

railway add postgresql
Railway automatically sets DATABASE_URL.
4

Configure backend service

Create railway.json in apps/backend:
railway.json
{
  "build": {
    "builder": "dockerfile",
    "dockerfilePath": "Dockerfile"
  },
  "deploy": {
    "startCommand": "node dist/server.js",
    "restartPolicyType": "on_failure"
  }
}
5

Set environment variables

railway variables set JWT_SECRET=your-secret-key
railway variables set FRONTEND_URL=https://your-app.railway.app
railway variables set NODE_ENV=production
6

Deploy

railway up
7

Run migrations

railway run npx prisma migrate deploy
Railway provides automatic HTTPS and custom domains.

Render Deployment

Backend on Render

1

Connect GitHub repository

  1. Go to Render Dashboard
  2. Click “New +” → “Web Service”
  3. Connect your GitHub repository
2

Configure service

  • Name: tambo360-backend
  • Environment: Docker
  • Dockerfile Path: apps/backend/Dockerfile
  • Docker Context Directory: apps/backend
3

Add environment variables

NODE_ENV=production
DATABASE_URL=<from-render-postgresql>
JWT_SECRET=<your-secret>
FRONTEND_URL=https://tambo360.onrender.com
4

Add PostgreSQL database

  1. Click “New +” → “PostgreSQL”
  2. Copy the Internal Database URL
  3. Add to backend environment variables
5

Deploy

Render automatically deploys on git push.

Frontend on Render

1

Create static site

  1. Click “New +” → “Static Site”
  2. Connect repository
2

Configure build

  • Build Command: cd apps/frontend && npm install && npm run build
  • Publish Directory: apps/frontend/dist
3

Add environment variables

VITE_API_URL=https://tambo360-backend.onrender.com/api

Vercel + Railway

Deploy frontend on Vercel and backend on Railway for optimal performance.

Frontend on Vercel

1

Install Vercel CLI

npm install -g vercel
vercel login
2

Configure project

Create vercel.json in apps/frontend:
vercel.json
{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "framework": "vite",
  "rewrites": [
    { "source": "/(.*)", "destination": "/" }
  ]
}
3

Set environment variables

vercel env add VITE_API_URL production
# Enter: https://your-backend.railway.app/api
4

Deploy

cd apps/frontend
vercel --prod

Backend on Railway

Follow the Railway deployment steps above for the backend.

AWS Deployment

Deploy using AWS ECS (Elastic Container Service) and RDS (PostgreSQL).

Prerequisites

  • AWS Account
  • AWS CLI installed
  • Docker images pushed to ECR

Architecture

  • Frontend: S3 + CloudFront
  • Backend: ECS Fargate
  • Database: RDS PostgreSQL
  • Secrets: AWS Secrets Manager
1

Create RDS PostgreSQL instance

aws rds create-db-instance \
  --db-instance-identifier tambo360-db \
  --db-instance-class db.t3.micro \
  --engine postgres \
  --engine-version 15.3 \
  --master-username postgres \
  --master-user-password <secure-password> \
  --allocated-storage 20
2

Push Docker images to ECR

# Create ECR repository
aws ecr create-repository --repository-name tambo360-backend

# Build and push
docker build -t tambo360-backend ./apps/backend
docker tag tambo360-backend:latest <account-id>.dkr.ecr.<region>.amazonaws.com/tambo360-backend:latest
docker push <account-id>.dkr.ecr.<region>.amazonaws.com/tambo360-backend:latest
3

Create ECS cluster and service

Use AWS Console or Terraform to create:
  • ECS Cluster
  • Task Definition (with environment variables)
  • ECS Service with Load Balancer
4

Deploy frontend to S3

cd apps/frontend
npm run build
aws s3 sync dist/ s3://tambo360-frontend

# Configure CloudFront distribution
aws cloudfront create-distribution --origin-domain-name tambo360-frontend.s3.amazonaws.com

SSL/TLS Configuration

Using Let’s Encrypt with Nginx

1

Install Certbot

sudo apt install certbot python3-certbot-nginx
2

Obtain SSL certificate

sudo certbot --nginx -d api.tambo360.com -d app.tambo360.com
3

Auto-renewal

# Test renewal
sudo certbot renew --dry-run

# Certbot creates a cron job automatically

Database Migrations in Production

Always backup your database before running migrations in production.
# 1. Backup database
pg_dump -U postgres -h db-host -d tambo > backup_$(date +%Y%m%d).sql

# 2. Test migration in staging
pnpm prisma migrate deploy --preview-feature

# 3. Apply to production
pnpm prisma migrate deploy

# 4. Verify
pnpm prisma migrate status

Monitoring and Logging

Health Check Endpoint

The backend includes a health check at /api/health:
app.get('/api/health', (req, res) => {
  res.status(200).json({ status: 'healthy', timestamp: new Date() });
});

Setup Monitoring

# Install PM2
npm install -g pm2

# Start backend with PM2
pm2 start dist/server.js --name tambo360-backend

# Monitor
pm2 monit

# View logs
pm2 logs

Performance Optimization

Enable Gzip

Nginx configuration:
gzip on;
gzip_types text/plain text/css application/json;

Database Connection Pooling

Configure in DATABASE_URL:
?connection_limit=10&pool_timeout=10

CDN for Static Assets

Use CloudFront, Cloudflare, or Vercel Edge Network

Redis Caching

Cache frequently accessed data:
docker run -d --name redis -p 6379:6379 redis:7

Backup Strategy

Automated Database Backups

backup.sh
#!/bin/bash

# Database backup script
BACKUP_DIR="/backups/tambo360"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/tambo_$DATE.sql"

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup database
pg_dump $DATABASE_URL > $BACKUP_FILE

# Compress
gzip $BACKUP_FILE

# Upload to S3 (optional)
aws s3 cp $BACKUP_FILE.gz s3://tambo360-backups/

# Delete backups older than 30 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete

echo "Backup completed: $BACKUP_FILE.gz"
Schedule with cron:
# Run daily at 2 AM
0 2 * * * /usr/local/bin/backup.sh

Rollback Strategy

1

Keep previous Docker images

docker tag tambo360-backend:latest tambo360-backend:previous
2

Rollback deployment

docker compose down
docker tag tambo360-backend:previous tambo360-backend:latest
docker compose up -d
3

Rollback database migrations

# Restore from backup
psql $DATABASE_URL < backup_20260308.sql

Security Hardening

  • Use AWS Secrets Manager, HashiCorp Vault, or Railway secrets
  • Rotate secrets regularly
  • Never log sensitive values
server {
  listen 80;
  return 301 https://$host$request_uri;
}
Use express-rate-limit:
import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100
});

app.use('/api', limiter);
Already configured in nginx.conf:
  • X-Frame-Options
  • X-Content-Type-Options
  • Content-Security-Policy

CI/CD Pipeline

GitHub Actions Example

.github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Build Docker images
        run: |
          docker build -t tambo360-backend ./apps/backend
          docker build -t tambo360-frontend ./apps/frontend
      
      - name: Run tests
        run: |
          cd apps/backend && npm test
          cd apps/frontend && npm test
      
      - name: Deploy to Railway
        env:
          RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
        run: |
          npm install -g @railway/cli
          railway up
      
      - name: Run migrations
        run: railway run npx prisma migrate deploy

Troubleshooting

Check backend health:
curl http://localhost:3000/api/health
docker compose logs backend
  • Check DATABASE_URL is correct
  • Verify database is accepting connections
  • Check firewall rules
  • Increase connection timeout in DATABASE_URL
Update CORS_ORIGIN to match production frontend URL:
CORS_ORIGIN=https://app.tambo360.com

Post-Deployment

1

Verify deployment

  • Frontend loads correctly
  • API health check responds
  • Database connections working
  • Authentication flows functional
  • Email sending operational
2

Monitor metrics

  • Response times
  • Error rates
  • Database query performance
  • Memory/CPU usage
3

Setup alerts

Configure alerts for:
  • Application downtime
  • High error rates
  • Database connection failures
  • Disk space warnings

Next Steps

Monitoring Guide

Set up comprehensive monitoring

API Reference

Explore available endpoints

Build docs developers (and LLMs) love