Complete guide for deploying VideoGen Messenger to production.
- Prerequisites
- AWS Infrastructure Setup
- Environment Configuration
- Database Setup
- Redis Setup
- Elasticsearch Setup
- CDN Configuration
- Application Deployment
- Production Checklist
- AWS account with appropriate permissions
- Domain name registered
- SSL certificate (AWS Certificate Manager)
- GitHub account for CI/CD (optional)
- AWS CLI v2+
- Docker and Docker Compose
- Node.js 18+ and npm 9+
- PostgreSQL client
- kubectl (for Kubernetes deployment)
# Create VPC
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=videogen-vpc}]'
# Create subnets (public and private)
aws ec2 create-subnet --vpc-id <vpc-id> --cidr-block 10.0.1.0/24 --availability-zone us-east-1a
aws ec2 create-subnet --vpc-id <vpc-id> --cidr-block 10.0.2.0/24 --availability-zone us-east-1b
# Create Internet Gateway
aws ec2 create-internet-gateway --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=videogen-igw}]'
# Attach to VPC
aws ec2 attach-internet-gateway --vpc-id <vpc-id> --internet-gateway-id <igw-id>Create buckets for video storage:
# Video storage bucket
aws s3 mb s3://videogen-videos-prod --region us-east-1
# Thumbnail storage bucket
aws s3 mb s3://videogen-thumbnails-prod --region us-east-1
# Configure bucket policies
aws s3api put-bucket-policy --bucket videogen-videos-prod --policy file://s3-policy.json
# Enable versioning (recommended)
aws s3api put-bucket-versioning --bucket videogen-videos-prod --versioning-configuration Status=Enabled
# Configure CORS
aws s3api put-bucket-cors --bucket videogen-videos-prod --cors-configuration file://cors-config.jsonExample s3-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::videogen-videos-prod/*",
"Condition": {
"StringLike": {
"aws:Referer": ["https://yourdomain.com/*"]
}
}
}
]
}# Create distribution
aws cloudfront create-distribution --distribution-config file://cloudfront-config.json
# Invalidate cache when needed
aws cloudfront create-invalidation --distribution-id <dist-id> --paths "/*"Example cloudfront-config.json:
{
"CallerReference": "videogen-cdn-1",
"Origins": {
"Quantity": 1,
"Items": [
{
"Id": "S3-videogen-videos",
"DomainName": "videogen-videos-prod.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
}
}
]
},
"DefaultCacheBehavior": {
"TargetOriginId": "S3-videogen-videos",
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": {
"Quantity": 2,
"Items": ["GET", "HEAD"]
},
"Compress": true,
"DefaultTTL": 86400
},
"Enabled": true
}# Create RDS instance
aws rds create-db-instance \
--db-instance-identifier videogen-db-prod \
--db-instance-class db.t3.medium \
--engine postgres \
--engine-version 15.3 \
--master-username admin \
--master-user-password <secure-password> \
--allocated-storage 100 \
--vpc-security-group-ids <sg-id> \
--db-subnet-group-name videogen-db-subnet \
--backup-retention-period 7 \
--preferred-backup-window "03:00-04:00" \
--multi-az \
--storage-encrypted \
--kms-key-id <kms-key-id>
# Create read replica (optional, for scaling)
aws rds create-db-instance-read-replica \
--db-instance-identifier videogen-db-replica \
--source-db-instance-identifier videogen-db-prod \
--db-instance-class db.t3.medium# Create Redis cluster
aws elasticache create-replication-group \
--replication-group-id videogen-redis-prod \
--replication-group-description "VideoGen Redis Cluster" \
--engine redis \
--cache-node-type cache.t3.medium \
--num-cache-clusters 2 \
--automatic-failover-enabled \
--at-rest-encryption-enabled \
--transit-encryption-enabled \
--auth-token <secure-token> \
--cache-subnet-group-name videogen-cache-subnet# Create OpenSearch domain
aws opensearch create-domain \
--domain-name videogen-search-prod \
--engine-version "OpenSearch_2.9" \
--cluster-config InstanceType=t3.medium.search,InstanceCount=2 \
--ebs-options EBSEnabled=true,VolumeType=gp3,VolumeSize=100 \
--vpc-options SubnetIds=<subnet-id>,SecurityGroupIds=<sg-id> \
--encryption-at-rest-options Enabled=true \
--node-to-node-encryption-options Enabled=true \
--access-policies file://opensearch-policy.jsonCreate .env.production:
# Application
NODE_ENV=production
PORT=3000
API_VERSION=v1
# Database
DATABASE_URL=postgresql://admin:password@videogen-db-prod.rds.amazonaws.com:5432/videogen
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
DATABASE_SSL=true
# Redis
REDIS_URL=redis://:auth-token@videogen-redis-prod.cache.amazonaws.com:6379
REDIS_TLS=true
REDIS_DB=0
# Elasticsearch
ELASTICSEARCH_NODE=https://videogen-search-prod.us-east-1.es.amazonaws.com
ELASTICSEARCH_USERNAME=admin
ELASTICSEARCH_PASSWORD=<secure-password>
ELASTICSEARCH_INDEX=videos
# AWS
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=<access-key>
AWS_SECRET_ACCESS_KEY=<secret-key>
AWS_S3_BUCKET_VIDEOS=videogen-videos-prod
AWS_S3_BUCKET_THUMBNAILS=videogen-thumbnails-prod
AWS_CLOUDFRONT_DOMAIN=d1234567890.cloudfront.net
# AI Providers
GOOGLE_VEO_API_KEY=<veo-api-key>
RUNWAY_API_KEY=<runway-api-key>
MINIMAX_API_KEY=<minimax-api-key>
AZURE_OPENAI_KEY=<azure-key>
AZURE_OPENAI_ENDPOINT=<azure-endpoint>
# Security
JWT_SECRET=<strong-random-secret-min-32-chars>
JWT_EXPIRY=24h
API_KEY_SALT=<strong-random-salt-min-32-chars>
ENCRYPTION_KEY=<strong-random-key-32-chars>
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
# Monitoring
SENTRY_DSN=<sentry-dsn>
NEW_RELIC_LICENSE_KEY=<newrelic-key>
LOG_LEVEL=infoUse AWS Secrets Manager:
# Store database credentials
aws secretsmanager create-secret \
--name videogen/database \
--secret-string '{"username":"admin","password":"<secure-password>"}'
# Store API keys
aws secretsmanager create-secret \
--name videogen/api-keys \
--secret-string '{"veo":"<key>","runway":"<key>","minimax":"<key>"}'
# Store JWT secret
aws secretsmanager create-secret \
--name videogen/jwt-secret \
--secret-string '{"secret":"<strong-random-secret>"}'# Connect to database
psql postgresql://admin:password@videogen-db-prod.rds.amazonaws.com:5432/postgres
# Create database
CREATE DATABASE videogen;
# Create extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";# Install migration tool
npm install -g db-migrate
# Run migrations
cd backend
db-migrate up --config database.json -e production
# Or using custom migration script
npm run migrate:production# Manual backup
pg_dump -h videogen-db-prod.rds.amazonaws.com -U admin -d videogen > backup.sql
# Restore from backup
psql -h videogen-db-prod.rds.amazonaws.com -U admin -d videogen < backup.sql
# Automated backups are configured in RDS (7-day retention)# Connect to Redis
redis-cli -h videogen-redis-prod.cache.amazonaws.com -p 6379 --tls -a <auth-token>
# Test connection
PING
# Set up key namespaces
# Cache keys: cache:*
# Queue keys: bull:*
# Session keys: session:*# Create videos index
curl -X PUT "https://videogen-search-prod.us-east-1.es.amazonaws.com/videos" \
-u admin:password \
-H 'Content-Type: application/json' \
-d @index-mapping.jsonSee backend/services/search/SearchService.js for index mapping configuration.
-
Origin Settings:
- Origin Domain: S3 bucket domain
- Origin Path:
/ - Origin Access Identity: Create new
-
Cache Behavior:
- Viewer Protocol: Redirect HTTP to HTTPS
- Allowed HTTP Methods: GET, HEAD
- Cache TTL: 86400 seconds (24 hours)
- Compress Objects: Yes
-
Distribution Settings:
- Price Class: Use All Edge Locations
- Alternate Domain Names (CNAMEs): videos.yourdomain.com
- SSL Certificate: Custom SSL (ACM)
# Build Docker image
docker build -t videogen-backend:latest ./backend
# Tag for ECR
docker tag videogen-backend:latest <account-id>.dkr.ecr.us-east-1.amazonaws.com/videogen-backend:latest
# Push to ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <account-id>.dkr.ecr.us-east-1.amazonaws.com
docker push <account-id>.dkr.ecr.us-east-1.amazonaws.com/videogen-backend:latest
# Deploy to ECS
aws ecs update-service --cluster videogen-cluster --service videogen-backend --force-new-deployment# Apply configurations
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secrets.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml
# Check deployment
kubectl get pods -n videogen
kubectl logs -f <pod-name> -n videogen# SSH to EC2 instance
ssh -i key.pem ec2-user@<instance-ip>
# Clone repository
git clone https://github.com/yourusername/videogen-messenger.git
cd videogen-messenger/backend
# Install dependencies
npm ci --production
# Set up PM2
npm install -g pm2
pm2 start ecosystem.config.js --env production
# Configure nginx reverse proxy
sudo nano /etc/nginx/sites-available/videogen
sudo ln -s /etc/nginx/sites-available/videogen /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx- All environment variables configured
- Database migrations tested
- Elasticsearch index created
- S3 buckets created and configured
- CloudFront distribution created
- SSL certificates installed
- Secrets stored in AWS Secrets Manager
- Monitoring and logging configured
- Backup strategy in place
- Security groups configured
- Load balancer health checks configured
- Verify application is running
- Test all API endpoints
- Verify database connections
- Test video generation flow
- Test search functionality
- Verify CDN is serving content
- Check monitoring dashboards
- Review application logs
- Test rate limiting
- Verify SSL/TLS
- Run smoke tests
- Configure auto-scaling
- All secrets rotated from defaults
- Database not publicly accessible
- Redis requires authentication
- Elasticsearch requires authentication
- S3 buckets not publicly listable
- IAM roles follow least privilege
- Security groups properly configured
- VPC properly configured
- WAF rules configured (if applicable)
- DDoS protection enabled
# CPU utilization alarm
aws cloudwatch put-metric-alarm \
--alarm-name videogen-high-cpu \
--alarm-description "Alert when CPU exceeds 80%" \
--metric-name CPUUtilization \
--namespace AWS/ECS \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2
# Memory utilization alarm
aws cloudwatch put-metric-alarm \
--alarm-name videogen-high-memory \
--alarm-description "Alert when memory exceeds 80%" \
--metric-name MemoryUtilization \
--namespace AWS/ECS \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2# List task definitions
aws ecs list-task-definitions --family-prefix videogen-backend
# Update service to previous version
aws ecs update-service \
--cluster videogen-cluster \
--service videogen-backend \
--task-definition videogen-backend:previous-version# Restore from automated backup
aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier videogen-db-prod \
--target-db-instance-identifier videogen-db-restored \
--restore-time 2024-01-15T10:00:00Z# Create Auto Scaling policy
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/videogen-cluster/videogen-backend \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 2 \
--max-capacity 10
# Create scaling policy
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/videogen-cluster/videogen-backend \
--scalable-dimension ecs:service:DesiredCount \
--policy-name videogen-scale-policy \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration file://scaling-policy.jsonSee TROUBLESHOOTING.md for common issues and solutions.