Skip to main content

Overview

This guide covers production deployment of the CS Interview Assistant, including server configuration, security hardening, and scaling considerations.
This is a production deployment guide. For local development, see the RUN_GUIDE.md in the source repository.

Pre-Deployment Checklist

Before deploying to production, ensure you have:
  • Server meeting hardware requirements
  • Valid Mistral AI API key with sufficient credits
  • Domain name and SSL certificate
  • PostgreSQL database server (recommended)
  • Backup strategy in place
  • Monitoring and logging infrastructure

Server Requirements

Compute

  • 4+ CPU cores (3.0 GHz+)
  • 16+ GB RAM
  • 50+ GB SSD storage

Network

  • Static IP address
  • 100 Mbps+ bandwidth
  • WebSocket support

Operating System

Recommended: Ubuntu Server 22.04 LTS or later
# Update system
sudo apt update && sudo apt upgrade -y

# Install essential packages
sudo apt install -y python3.10 python3-pip python3-venv \
  nodejs npm postgresql postgresql-contrib \
  nginx supervisor git build-essential

Step 1: Environment Setup

1.1 Create Application User

# Create dedicated user for security
sudo useradd -m -s /bin/bash interview
sudo usermod -aG sudo interview

1.2 Clone Repository

sudo su - interview
git clone <repository-url> /home/interview/app
cd /home/interview/app

1.3 Configure Environment Variables

Create production .env file:
cd /home/interview/app/backend
touch .env
chmod 600 .env  # Secure permissions
Add production configuration:
# AI Configuration
MISTRAL_API_KEY=<your-production-mistral-key>
MISTRAL_MODEL=mistral-large-latest

# Security (GENERATE NEW KEYS!)
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
JWT_SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")

# Database
DATABASE_URL=postgresql://interview_user:secure_password@localhost:5432/interview_db

# Optional: AssemblyAI for voice interviews
ASSEMBLYAI_API_KEY=<your-assemblyai-key>
Never use default security keys in production! Generate unique keys using the commands shown above.

Step 2: Database Setup

2.1 Install and Configure PostgreSQL

# PostgreSQL should already be installed from Step 1
sudo systemctl start postgresql
sudo systemctl enable postgresql

2.2 Create Database and User

# Switch to postgres user
sudo -u postgres psql
-- Create database
CREATE DATABASE interview_db;

-- Create user with strong password
CREATE USER interview_user WITH ENCRYPTED PASSWORD 'your_secure_password_here';

-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE interview_db TO interview_user;

-- Exit
\q

2.3 Update Application Configuration

Modify backend/config.py to use PostgreSQL:
class Config:
    # Use environment variable for database URL
    SQLALCHEMY_DATABASE_URI = os.getenv(
        'DATABASE_URL', 
        'sqlite:///interview_prep.db'  # Fallback for development
    )
    SQLALCHEMY_TRACK_MODIFICATIONS = False

2.4 Migrate from SQLite (If Applicable)

If migrating from SQLite development database:
# Export data from SQLite
sqlite3 instance/interview_prep.db .dump > backup.sql

# Convert and import to PostgreSQL
# (This requires manual SQL conversion for schema differences)
For production deployments, use PostgreSQL from the start to avoid migration complexity.

Step 3: Backend Setup

3.1 Create Virtual Environment

cd /home/interview/app/backend
python3 -m venv venv
source venv/bin/activate

3.2 Install Dependencies

pip install --upgrade pip
pip install -r requirements.txt

# For production, also install Gunicorn
pip install gunicorn eventlet

3.3 Build Knowledge Base

# Prepare knowledge base
python scripts/prepare_kb.py

# Build FAISS indices
python scripts/reindex_mistral.py
FAISS index building can take 10-30 minutes depending on knowledge base size and server specs.

3.4 Initialize Database

# Run migrations and create tables
python backend/app.py
# Press Ctrl+C after seeing "Database initialized"

3.5 Configure Gunicorn

Create gunicorn_config.py in backend directory:
import multiprocessing

# Server socket
bind = '127.0.0.1:8000'
backlog = 2048

# Worker processes
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'eventlet'
worker_connections = 1000
timeout = 300  # 5 minutes for long-running AI operations
keepalive = 2

# Logging
accesslog = '/var/log/interview/gunicorn_access.log'
errorlog = '/var/log/interview/gunicorn_error.log'
loglevel = 'info'

# Process naming
proc_name = 'interview_backend'

# Server mechanics
daemon = False
pidfile = '/var/run/interview/gunicorn.pid'
user = 'interview'
group = 'interview'
Create log directory:
sudo mkdir -p /var/log/interview /var/run/interview
sudo chown interview:interview /var/log/interview /var/run/interview

Step 4: Frontend Build

4.1 Install Dependencies

cd /home/interview/app/frontend
npm install --production

4.2 Build Production Bundle

npm run build
This creates an optimized production build in frontend/build/.

4.3 Configure API Endpoint

Update frontend/src/config.js (or equivalent) to point to production backend:
const API_BASE_URL = process.env.REACT_APP_API_URL || 'https://api.yourdomain.com';
const WS_BASE_URL = process.env.REACT_APP_WS_URL || 'wss://api.yourdomain.com';

Step 5: Nginx Configuration

5.1 Install and Configure Nginx

sudo apt install nginx -y
Create Nginx configuration /etc/nginx/sites-available/interview:
# Upstream backend
upstream backend {
    server 127.0.0.1:8000 fail_timeout=0;
}

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    
    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;
    
    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    # Static files (React frontend)
    location / {
        root /home/interview/app/frontend/build;
        try_files $uri $uri/ /index.html;
        
        # Cache static assets
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    }
    
    # Backend API
    location /api {
        proxy_pass http://backend;
        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;
        
        # Increase timeout for AI operations
        proxy_read_timeout 300s;
        proxy_connect_timeout 300s;
    }
    
    # WebSocket support
    location /socket.io {
        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;
        
        # WebSocket timeout
        proxy_read_timeout 3600s;
    }
    
    # File uploads
    client_max_body_size 16M;
}

5.2 Enable Configuration

sudo ln -s /etc/nginx/sites-available/interview /etc/nginx/sites-enabled/
sudo nginx -t  # Test configuration
sudo systemctl restart nginx
sudo systemctl enable nginx

Step 6: SSL/TLS Certificate

6.1 Install Certbot

sudo apt install certbot python3-certbot-nginx -y

6.2 Obtain Certificate

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the prompts to:
  • Enter email address
  • Agree to terms
  • Choose to redirect HTTP to HTTPS

6.3 Auto-Renewal

Certbot automatically sets up renewal. Test it:
sudo certbot renew --dry-run

Step 7: Process Management

7.1 Create Supervisor Configuration

Create /etc/supervisor/conf.d/interview.conf:
[program:interview_backend]
command=/home/interview/app/backend/venv/bin/gunicorn -c gunicorn_config.py app:app
directory=/home/interview/app/backend
user=interview
autostart=true
autorestart=true
startretries=3
redirect_stderr=true
stdout_logfile=/var/log/interview/supervisor.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=10
environment=PATH="/home/interview/app/backend/venv/bin"

7.2 Start Services

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start interview_backend
sudo supervisorctl status

7.3 Enable Supervisor on Boot

sudo systemctl enable supervisor

Step 8: CORS Configuration

Update backend/app.py CORS settings for production:
from flask_cors import CORS

# Replace:
# CORS(app, supports_credentials=True)

# With:
CORS(app, 
     supports_credentials=True,
     origins=[
         'https://yourdomain.com',
         'https://www.yourdomain.com'
     ],
     allow_headers=['Content-Type', 'Authorization'],
     expose_headers=['Content-Type', 'Authorization'],
     methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
)

Step 9: Monitoring and Logging

9.1 Application Logs

Centralize logging:
# View backend logs
sudo tail -f /var/log/interview/gunicorn_access.log
sudo tail -f /var/log/interview/gunicorn_error.log

# View Nginx logs
sudo tail -f /var/nginx/access.log
sudo tail -f /var/nginx/error.log

9.2 System Monitoring

Install monitoring tools:
# Install htop for system monitoring
sudo apt install htop -y

# Install prometheus-node-exporter (optional)
sudo apt install prometheus-node-exporter -y

9.3 Log Rotation

Create /etc/logrotate.d/interview:
/var/log/interview/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 interview interview
    sharedscripts
    postrotate
        supervisorctl restart interview_backend > /dev/null 2>&1
    endscript
}

Step 10: Backup Strategy

10.1 Database Backups

Create backup script /home/interview/backup_db.sh:
#!/bin/bash
BACKUP_DIR="/home/interview/backups/db"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR
pg_dump -U interview_user interview_db | gzip > $BACKUP_DIR/interview_db_$DATE.sql.gz

# Keep only last 30 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
Make executable and schedule:
chmod +x /home/interview/backup_db.sh

# Add to crontab (daily at 2 AM)
crontab -e
0 2 * * * /home/interview/backup_db.sh

10.2 FAISS Index Backups

#!/bin/bash
BACKUP_DIR="/home/interview/backups/faiss"
SOURCE_DIR="/home/interview/app/data/processed/faiss_mistral"
DATE=$(date +%Y%m%d)

mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/faiss_index_$DATE.tar.gz -C $SOURCE_DIR .

# Keep only last 7 days (large files)
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete

10.3 User Uploads Backups

rsync -av --delete /home/interview/app/uploads/ /home/interview/backups/uploads/

Security Hardening

11.1 Firewall Configuration

# Install UFW
sudo apt install ufw -y

# Allow SSH, HTTP, HTTPS
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Enable firewall
sudo ufw enable
sudo ufw status

11.2 Fail2Ban (Optional)

Protect against brute-force attacks:
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

11.3 Disable Directory Listing

In Nginx config, add:
autoindex off;

11.4 Rate Limiting

Add to Nginx config:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

location /api {
    limit_req zone=api burst=20 nodelay;
    # ... rest of config
}

location /api/login {
    limit_req zone=login burst=3 nodelay;
    # ... rest of config
}

Scaling Considerations

12.1 Horizontal Scaling

For high traffic, consider:
  1. Multiple Gunicorn workers: Already configured in gunicorn_config.py
  2. Load balancer: Use Nginx upstream with multiple backend servers
  3. Redis for sessions: Replace Flask sessions with Redis-backed sessions
  4. Separate FAISS server: Move RAG to dedicated service

12.2 Vertical Scaling

Monitor and upgrade:
  • RAM: Most critical for FAISS indices (add 8GB per 100k documents)
  • CPU: Increase cores for concurrent user sessions
  • Storage: Monitor growth of uploads and database

12.3 Caching

Implement caching for:
  • Static files: Already handled by Nginx
  • API responses: Use Flask-Caching
  • FAISS queries: Cache frequent queries in Redis

Troubleshooting

Backend Not Starting

# Check supervisor logs
sudo supervisorctl tail interview_backend stderr

# Check Gunicorn logs
tail -f /var/log/interview/gunicorn_error.log

# Test manually
cd /home/interview/app/backend
source venv/bin/activate
python app.py

Database Connection Errors

# Verify PostgreSQL is running
sudo systemctl status postgresql

# Test connection
psql -U interview_user -d interview_db -h localhost

# Check DATABASE_URL in .env
cat backend/.env | grep DATABASE_URL

Nginx 502 Bad Gateway

# Check if backend is running
sudo supervisorctl status interview_backend

# Check backend is listening
sudo netstat -tulpn | grep 8000

# Check Nginx error log
sudo tail -f /var/log/nginx/error.log

WebSocket Connection Failed

  • Verify Nginx WebSocket configuration
  • Check firewall allows port 443
  • Ensure SSL certificate is valid
  • Test with: wscat -c wss://yourdomain.com/socket.io

Performance Optimization

Enable Gzip Compression

In Nginx config:
gzip on;
gzip_vary on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

Database Connection Pooling

Add to config.py:
SQLALCHEMY_ENGINE_OPTIONS = {
    'pool_size': 10,
    'pool_recycle': 3600,
    'pool_pre_ping': True,
}

Health Checks

Create health check endpoint in app.py:
@app.route('/health')
def health_check():
    return jsonify({
        'status': 'healthy',
        'database': 'connected' if db.session.execute('SELECT 1').scalar() == 1 else 'error',
        'timestamp': datetime.utcnow().isoformat()
    })

Next Steps

Requirements

Review system requirements

Environment Variables

Configure application settings

Build docs developers (and LLMs) love