Overview
This guide covers deploying the Cognit Backend API to production, including building the application, configuring environment variables, and implementing security best practices.
Building for Production
The application is written in TypeScript and must be compiled to JavaScript before deployment.
Build the application
This command:
Runs the TypeScript compiler (tsc)
Compiles all .ts files in src/ to JavaScript
Outputs compiled files to the dist/ directory
Uses configuration from tsconfig.json
Verify the build
Check that the dist/ directory was created: You should see compiled JavaScript files matching your source structure.
Test the production build locally
This runs node ./dist/index.js (package.json:9)
The dist/ directory should be added to .gitignore - never commit compiled code.
Production Environment Variables
Create a .env file for production with secure values:
# Server Configuration
PORT = 3005
NODE_ENV = production
# Database - Use production PostgreSQL instance
DATABASE_URL = postgresql://prod_user:SECURE_PASSWORD@prod-db-host:5432/cognit_production
# JWT - Use a strong, unique secret
JWT_SECRET = GENERATE_A_SECURE_RANDOM_STRING_MINIMUM_64_CHARACTERS
# Email - Production SMTP credentials
EMAIL_HOST = smtp.sendgrid.net
EMAIL_PORT = 587
EMAIL_USER = apikey
EMAIL_PASS = YOUR_SENDGRID_API_KEY
# Frontend - Production domain
FRONTEND_URL = https://cognit.website
Security Checklist:
Use unique JWT_SECRET (minimum 64 characters)
Use strong database passwords (16+ characters, mixed case, numbers, symbols)
Never reuse development credentials in production
Store secrets securely (use secret managers like AWS Secrets Manager, HashiCorp Vault)
Never commit .env files to version control
Generating Secure Secrets
# Generate a secure JWT secret
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
# Generate a secure database password
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
Database Setup
Production Database Configuration
Create production database
On your production PostgreSQL server: CREATE DATABASE cognit_production ;
CREATE USER cognit_prod WITH PASSWORD 'SECURE_RANDOM_PASSWORD' ;
GRANT ALL PRIVILEGES ON DATABASE cognit_production TO cognit_prod;
Update database sync mode
The development server uses db.sync({ alter: true }) which is not safe for production . Modify src/server.ts for production: async function connectDB () {
try {
await db . authenticate ()
// Only sync in development
if ( process . env . NODE_ENV !== 'production' ) {
db . sync ({ alter: true })
}
console . log ( colors . blue . bold ( 'Database connection successfull' ))
} catch ( error ) {
console . log ( colors . red ( 'Database connection failed' ))
}
}
Initialize database schema
For the first deployment, you can temporarily enable sync: NODE_ENV = development npm start
# Tables will be created
# Then stop the server and switch to NODE_ENV=production
Or manually create tables based on your Sequelize models.
Running the Production Server
Available Scripts
From package.json:
Script Command Purpose npm run devnodemon src/index.tsDevelopment with auto-reload npm run dev:apinodemon src/index.ts --apiDevelopment in API mode npm run buildtscCompile TypeScript to JavaScript npm startnode ./dist/index.jsRun production server npm testjestRun tests
Starting the Server
Direct Execution
With PM2 (Recommended)
With Docker
# After running npm run build
npm start
PM2 provides:
Automatic restarts on crashes
Load balancing (cluster mode)
Log management
Zero-downtime deployments
Security Considerations
The application implements several security measures that are automatically enabled:
Location : src/server.ts:26
Helmet sets HTTP headers to protect against common vulnerabilities:
Prevents clickjacking (X-Frame-Options)
Blocks MIME-type sniffing (X-Content-Type-Options)
Enables XSS protection
Content Security Policy
2. CORS (Cross-Origin Resource Sharing)
app . use ( cors ({
origin: [ 'https://cognit.website' , 'http://localhost:5175' ],
credentials: true ,
}));
Location : src/server.ts:27-30
Production CORS Configuration:
Remove localhost origins
Only allow your production frontend domain
Keep credentials: true for cookie-based auth
app . use ( cors ({
origin: [ 'https://cognit.website' , 'https://app.cognit.website' ],
credentials: true ,
}));
3. Rate Limiting
export const limiter = rateLimit ({
windowMs: 60 * 1000 , // 1 minute
limit: 5 , // 5 requests
message: { "error" : "Max limit requests" }
})
Location : src/config/limiter.ts:3-7
Applied to : All /api/auth/* routes (src/routes/authRouter.ts:10)
Production Rate Limiting Recommendations: // Stricter limits for production
export const limiter = rateLimit ({
windowMs: 15 * 60 * 1000 , // 15 minutes
limit: 100 , // 100 requests
message: { "error" : "Too many requests, please try again later" },
standardHeaders: true ,
legacyHeaders: false ,
})
// Separate limiter for authentication
export const authLimiter = rateLimit ({
windowMs: 15 * 60 * 1000 ,
limit: 5 , // Only 5 login attempts per 15 min
message: { "error" : "Too many authentication attempts" }
})
4. JWT Authentication
Token Generation : src/utils/jwt.ts:3-7
Token Verification : src/middleware/auth.ts:31
Best practices:
Use long, random JWT_SECRET (64+ characters)
Tokens expire after 30 days (consider shorter for production)
Tokens transmitted via Authorization: Bearer <token> header
5. Password Hashing
The application uses bcrypt for password hashing:
Passwords are never stored in plaintext
Uses salt rounds for added security
Additional Security Recommendations
Enable HTTPS
Always use HTTPS in production. Use a reverse proxy like Nginx with Let’s Encrypt: server {
listen 443 ssl http2;
server_name api.cognit.website;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3005;
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 ;
}
}
Environment variable security
Never log environment variables
Use secret management services (AWS Secrets Manager, Azure Key Vault)
Rotate secrets regularly
Use different credentials for each environment
Database security
Use SSL/TLS for database connections
Restrict database access by IP
Use principle of least privilege for database users
Enable database audit logging
Monitoring and logging
Install monitoring tools: npm install winston # Structured logging
npm install @sentry/node # Error tracking
Docker Deployment
Create a Dockerfile:
FROM node:18-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy source code
COPY . .
# Build TypeScript
RUN npm run build
# Expose port
EXPOSE 3005
# Start application
CMD [ "npm" , "start" ]
Create docker-compose.yml:
version : '3.8'
services :
app :
build : .
ports :
- "3005:3005"
environment :
- NODE_ENV=production
- PORT=3005
- DATABASE_URL=postgresql://postgres:password@db:5432/cognit
- JWT_SECRET=${JWT_SECRET}
- EMAIL_HOST=${EMAIL_HOST}
- EMAIL_PORT=${EMAIL_PORT}
- EMAIL_USER=${EMAIL_USER}
- EMAIL_PASS=${EMAIL_PASS}
- FRONTEND_URL=${FRONTEND_URL}
depends_on :
- db
restart : unless-stopped
db :
image : postgres:15-alpine
environment :
- POSTGRES_DB=cognit
- POSTGRES_PASSWORD=password
volumes :
- postgres_data:/var/lib/postgresql/data
restart : unless-stopped
volumes :
postgres_data :
Deploy:
# Build and start
docker-compose up -d
# View logs
docker-compose logs -f app
# Stop
docker-compose down
# Install Heroku CLI
npm install -g heroku
# Login
heroku login
# Create app
heroku create cognit-backend
# Add PostgreSQL
heroku addons:create heroku-postgresql:mini
# Set environment variables
heroku config:set JWT_SECRET=your-secret
heroku config:set EMAIL_HOST=smtp.sendgrid.net
heroku config:set EMAIL_PORT= 587
heroku config:set EMAIL_USER=apikey
heroku config:set EMAIL_PASS=your-sendgrid-key
heroku config:set FRONTEND_URL=https://cognit.website
# Deploy
git push heroku main
# View logs
heroku logs --tail
Add Procfile:
Connect your GitHub repository to Railway
Add PostgreSQL plugin
Set environment variables in Railway dashboard
Deploy automatically on git push
Railway automatically detects Node.js and runs:
npm install
npm run build
npm start
Create new app from GitHub repository
Add managed PostgreSQL database
Configure environment variables
Set build command: npm run build
Set run command: npm start
Deploy
# SSH into EC2 instance
ssh -i key.pem ubuntu@your-ec2-ip
# Install Node.js
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# Clone repository
git clone < your-rep o >
cd backend
# Install dependencies
npm install
# Build
npm run build
# Install PM2
sudo npm install -g pm2
# Start with PM2
pm2 start dist/index.js --name cognit-backend
pm2 startup
pm2 save
Health Checks and Monitoring
Add a health check endpoint:
// src/server.ts
app . get ( '/health' , async ( req , res ) => {
try {
await db . authenticate ();
res . status ( 200 ). json ({
status: 'healthy' ,
database: 'connected' ,
timestamp: new Date (). toISOString ()
});
} catch ( error ) {
res . status ( 503 ). json ({
status: 'unhealthy' ,
database: 'disconnected' ,
error: error . message
});
}
});
Post-Deployment Checklist
Verify environment variables
All required variables are set
No development values in production
Secrets are secure and unique
Test API endpoints
curl https://api.cognit.website/health
curl https://api.cognit.website/api/auth/users
Check security headers
curl -I https://api.cognit.website/health
Verify headers like X-Frame-Options, X-Content-Type-Options, etc.
Verify CORS configuration
Test from your frontend application that requests are not blocked.
Monitor logs
Check for errors, warnings, or unusual activity.
Test rate limiting
Verify rate limits are working by making rapid requests.
Verify database connectivity
Check that all database operations work correctly.
Troubleshooting
Database Connection Issues
# Test DATABASE_URL format
node -e "console.log(process.env.DATABASE_URL)"
# Test connection with psql
psql " $DATABASE_URL "
Port Already in Use
# Find process using port 3005
lsof -i :3005
# Kill the process
kill -9 < PI D >
Build Failures
# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install
npm run build
Next Steps
API Reference Explore all available endpoints
Configuration Fine-tune your configuration