Complete deployment instructions for TAP (Training, Academics, and Placement).
- Pre-Deployment Checklist
- Environment Setup
- Vercel Deployment (Frontend)
- Railway Deployment (Backend)
- Docker Deployment
- Traditional VPS Deployment
- Database Migration
- Monitoring & Logging
- Troubleshooting
- All tests passing (
npm test) - No console errors or warnings
- ESLint checks passing (
npm run lint) - TypeScript compilation successful
- No hardcoded secrets or credentials
- Environment variables documented
- JWT secret is strong and unique
- CORS origins are properly configured
- HTTPS is enabled
- Database credentials are secure
- API rate limiting is configured
- Input validation is implemented
- Frontend bundle size optimized
- Images are compressed
- Database indexes are created
- Caching strategies implemented
- CDN configured for static assets
- README is up to date
- API documentation is complete
- Deployment steps are documented
- Environment variables are listed
- Troubleshooting guide is available
Backend .env.production:
# ============================================
# DATABASE
# ============================================
MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/tap?retryWrites=true&w=majority
# ============================================
# AUTHENTICATION
# ============================================
JWT_SECRET=your_very_strong_random_secret_key_here_minimum_32_characters
JWT_EXPIRE=7d
JWT_REFRESH_EXPIRE=30d
# ============================================
# SERVER
# ============================================
NODE_ENV=production
PORT=5000
HOST=0.0.0.0
# ============================================
# SECURITY
# ============================================
CORS_ORIGIN=https://your-domain.com,https://www.your-domain.com
ALLOWED_ORIGINS=https://your-domain.com
# ============================================
# EMAIL
# ============================================
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_app_password
# ============================================
# FILE UPLOAD
# ============================================
MAX_FILE_SIZE=10485760
UPLOAD_PATH=./uploads
# ============================================
# LOGGING
# ============================================
LOG_LEVEL=warnFrontend .env.production:
# ============================================
# API
# ============================================
VITE_API_URL=https://api.your-domain.com
VITE_API_TIMEOUT=10000
# ============================================
# APPLICATION
# ============================================
VITE_APP_NAME=TAP
VITE_APP_VERSION=1.0.0
# ============================================
# FEATURES
# ============================================
VITE_ENABLE_ANALYTICS=true
VITE_ENABLE_NOTIFICATIONS=true
VITE_ENABLE_DARK_MODE=true
# ============================================
# DEBUG
# ============================================
VITE_DEBUG=false# Build frontend
cd frontend
npm run build
# Test production build locally
npm run previewOption A: Using Vercel CLI
# Install Vercel CLI
npm i -g vercel
# Login to Vercel
vercel login
# Deploy
vercel --prodOption B: Using GitHub
- Push code to GitHub
- Go to Vercel Dashboard
- Click "New Project"
- Select your GitHub repository
- Configure build settings:
- Framework: Vite
- Build Command:
npm run build - Output Directory:
dist
- Add environment variables
- Click "Deploy"
In Vercel Dashboard:
- Go to Project Settings → Environment Variables
- Add production variables:
VITE_API_URL=https://api.your-domain.comVITE_APP_NAME=TAPVITE_ENABLE_ANALYTICS=true
- Go to Project Settings → Domains
- Add your custom domain
- Update DNS records (provided by Vercel)
- Wait for DNS propagation (up to 48 hours)
- Go to Project Settings → Git
- Enable "Automatic Deployments"
- Select branch (usually
main)
# Build backend
cd backend
npm run build
# Test production build
npm start- Go to Railway.app
- Sign up with GitHub
- Create new project
Using Railway CLI:
# Install Railway CLI
npm i -g @railway/cli
# Login
railway login
# Initialize project
cd backend
railway init
# Link to project
railway link
# Deploy
railway upUsing GitHub:
- Push code to GitHub
- In Railway Dashboard, click "New Project"
- Select "Deploy from GitHub"
- Choose your repository
- Configure build settings
In Railway Dashboard:
- Go to Project → Variables
- Add production variables:
MONGODB_URI=mongodb+srv://...JWT_SECRET=your_secretNODE_ENV=productionCORS_ORIGIN=https://your-domain.com
- Go to Project → Domains
- Add custom domain
- Update DNS records
Option A: MongoDB Atlas (Recommended)
- Create MongoDB Atlas cluster
- Get connection string
- Add to Railway variables as
MONGODB_URI
Option B: Railway PostgreSQL
- In Railway Dashboard, add PostgreSQL service
- Connect backend to PostgreSQL
- Update connection string
Frontend Dockerfile:
# Build stage
FROM node:18-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:18-alpine
WORKDIR /app
RUN npm install -g serve
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["serve", "-s", "dist", "-l", "3000"]Backend Dockerfile:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 5000
CMD ["npm", "start"]docker-compose.yml:
version: '3.8'
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- VITE_API_URL=http://backend:5000
depends_on:
- backend
networks:
- tap-network
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "5000:5000"
environment:
- MONGODB_URI=mongodb://mongo:27017/tap
- JWT_SECRET=${JWT_SECRET}
- NODE_ENV=production
depends_on:
- mongo
networks:
- tap-network
restart: unless-stopped
mongo:
image: mongo:6
ports:
- "27017:27017"
volumes:
- mongo_data:/data/db
environment:
- MONGO_INITDB_DATABASE=tap
networks:
- tap-network
restart: unless-stopped
volumes:
mongo_data:
networks:
tap-network:
driver: bridge# Build images
docker-compose build
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down# Login to Docker Hub
docker login
# Build image
docker build -t yourusername/tap-backend:1.0.0 ./backend
# Push to registry
docker push yourusername/tap-backend:1.0.0
# Pull and run
docker run -d \
-e MONGODB_URI=mongodb+srv://... \
-e JWT_SECRET=your_secret \
-p 5000:5000 \
yourusername/tap-backend:1.0.0SSH into server:
ssh root@your_server_ipUpdate system:
apt update && apt upgrade -yInstall Node.js:
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
apt install -y nodejsInstall MongoDB:
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list
apt update
apt install -y mongodb-org
systemctl start mongod
systemctl enable mongodInstall Nginx:
apt install -y nginx
systemctl start nginx
systemctl enable nginxClone repository:
cd /var/www
git clone https://github.com/yourusername/tap.git
cd tapInstall dependencies:
# Frontend
cd frontend
npm install
npm run build
cd ..
# Backend
cd backend
npm install
cd ..Create environment files:
# Backend
cd backend
nano .env
# Add production variables
# Frontend
cd ../frontend
nano .env
# Add production variablesInstall PM2:
npm install -g pm2Create PM2 ecosystem file:
cat > ecosystem.config.js << EOF
module.exports = {
apps: [
{
name: 'tap-backend',
script: './backend/server.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production'
},
error_file: './logs/backend-error.log',
out_file: './logs/backend-out.log'
},
{
name: 'tap-frontend',
script: 'npm',
args: 'start',
cwd: './frontend',
instances: 1,
exec_mode: 'fork',
env: {
NODE_ENV: 'production'
},
error_file: './logs/frontend-error.log',
out_file: './logs/frontend-out.log'
}
]
};
EOFStart applications:
pm2 start ecosystem.config.js
pm2 save
pm2 startupCreate Nginx config:
cat > /etc/nginx/sites-available/tap << 'EOF'
upstream backend {
server 127.0.0.1:5000;
}
upstream frontend {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name your-domain.com www.your-domain.com;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com www.your-domain.com;
# SSL certificates
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# Frontend
location / {
proxy_pass http://frontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# Backend API
location /api {
proxy_pass http://backend;
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;
}
}
EOFEnable site:
ln -s /etc/nginx/sites-available/tap /etc/nginx/sites-enabled/
nginx -t
systemctl restart nginx# Install Certbot
apt install -y certbot python3-certbot-nginx
# Get certificate
certbot certonly --standalone -d your-domain.com -d www.your-domain.com
# Auto-renewal
systemctl enable certbot.timer# Local MongoDB
mongodump --db tap --out ./backup
# MongoDB Atlas
mongodump --uri "mongodb+srv://username:password@cluster.mongodb.net/tap"# Local MongoDB
mongorestore ./backup
# MongoDB Atlas
mongorestore --uri "mongodb+srv://username:password@cluster.mongodb.net" ./backupUsing PM2 Monitoring:
# Install PM2 Plus
pm2 install pm2-auto-pull
# Monitor
pm2 monit
# View logs
pm2 logs tap-backend
pm2 logs tap-frontendUsing Sentry:
# Install Sentry
npm install @sentry/node
# Configure in backend
const Sentry = require('@sentry/node');
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV
});
app.use(Sentry.Handlers.errorHandler());Issue: Build fails on Vercel
Solution:
# Check build logs
# Ensure all dependencies are in package.json
# Verify environment variables are set
# Check Node version compatibilityIssue: Backend cannot connect to database
Solution:
# Verify MongoDB connection string
# Check IP whitelist in MongoDB Atlas
# Verify credentials
# Test connection locallyIssue: CORS errors in production
Solution:
# Update CORS_ORIGIN in .env
# Ensure frontend URL matches
# Check backend is running
# Clear browser cacheIssue: High memory usage
Solution:
# Check for memory leaks
# Optimize database queries
# Implement caching
# Scale horizontallyFor more help, visit GitHub Issues