Server Configuration & Deployment

Production deployment, security, and optimization guide

Production Environment Setup

This guide covers deploying ManageX in a production environment with proper security, performance, and monitoring configurations.

Server Requirements

  • CPU: 2+ cores (4+ recommended)
  • RAM: 8GB minimum (16GB+ recommended)
  • Storage: 50GB+ SSD storage
  • OS: Ubuntu 20.04 LTS or CentOS 8+
  • Network: Static IP address, domain name

Environment Configuration

Production .env Configuration

Create a .env file in the server directory with your production configuration:

Example .env File

# NODE Configuration
PORT=3000     
NODE_ENV=production

# Database Configuration
DB_HOST=localhost
DB_NAME=managex_db
DB_USERNAME=managex_user
DB_PASSWORD=your_secure_password
DB_DIALECT=mysql

# JWT Configuration
JWT_SECRET=your-super-secure-jwt-secret-key-change-this-in-production
JWT_REFRESH_SECRET=your-refresh-secret-key-change-in-production
JWT_EXPIRES_IN=24h
JWT_REFRESH_EXPIRES_IN=7d

# Demo Mode Configuration
IS_DEMO=0

Security Warning

Never commit the .env file to version control. Use environment-specific configuration files and secure secret management. Change all default secrets and passwords in production.

Production Checklist

  • Set NODE_ENV=production for optimal performance
  • Use strong, unique passwords for database and JWT secrets
  • Set IS_DEMO=0 to skip demo data seeders
  • Configure proper email settings for notifications
  • Update APP_URL to your production domain

Process Management

PM2 Configuration

Create ecosystem.config.js for production deployment:

module.exports = {
  apps: [{
    name: 'managex-server',
    script: './bin/www',
    instances: 'max', // Use all CPU cores
    exec_mode: 'cluster',
    autorestart: true,
    watch: false,
    max_memory_restart: '1G',
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    },
    error_file: './logs/err.log',
    out_file: './logs/out.log',
    log_file: './logs/combined.log',
    time: true,
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z'
  }]
};

Systemd Service

Create /etc/systemd/system/managex.service:

[Unit]
Description=ManageX Business Management System
After=network.target mysql.service
Requires=mysql.service

[Service]
Type=forking
User=www-data
Group=www-data
WorkingDirectory=/var/www/managex/server
ExecStart=/usr/bin/pm2 start ecosystem.config.js
ExecReload=/usr/bin/pm2 reload all
ExecStop=/usr/bin/pm2 stop all
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and Start Service

# Reload systemd
sudo systemctl daemon-reload

# Enable service to start on boot
sudo systemctl enable managex

# Start service
sudo systemctl start managex

# Check status
sudo systemctl status managex

Web Server Configuration

Nginx Configuration

Create /etc/nginx/sites-available/managex:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    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 ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;

    # Security Headers
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Rate Limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

    # API Routes
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://localhost:3000;
        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;
    }

    # Application (EJS server-side rendering)
    location / {
        proxy_pass http://localhost:3000;
        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;
    }

    # File uploads
    location /uploads/ {
        alias /var/www/managex/server/public/uploads/;
        expires 1y;
        add_header Cache-Control "public";
    }

    # Static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        root /var/www/managex/server/public;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Enable Nginx Site

# Create symbolic link
sudo ln -s /etc/nginx/sites-available/managex /etc/nginx/sites-enabled/

# Test configuration
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

Apache Configuration

Create /etc/apache2/sites-available/managex.conf:

<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com
    Redirect permanent / https://yourdomain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName yourdomain.com
    ServerAlias www.yourdomain.com

    # SSL Configuration
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/yourdomain.com/chain.pem

    # Security Headers
    Header always set X-Frame-Options DENY
    Header always set X-Content-Type-Options nosniff
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

    # API Proxy
    ProxyPreserveHost On
    ProxyPass /api/ http://localhost:3000/api/
    ProxyPassReverse /api/ http://localhost:3000/api/

    # Application Proxy
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

    # File uploads
    Alias /uploads /var/www/managex/server/public/uploads
    <Directory /var/www/managex/server/public/uploads>
        Options -Indexes
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

Enable Apache Modules and Site

# Enable required modules
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod rewrite

# Enable site
sudo a2ensite managex.conf

# Test configuration
sudo apache2ctl configtest

# Reload Apache
sudo systemctl reload apache2

SSL Certificate Setup

Let's Encrypt with Certbot

1

Install Certbot

# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx

# CentOS/RHEL
sudo yum install certbot python3-certbot-nginx
2

Obtain Certificate

# For Nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# For Apache
sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

Follow the prompts to complete the certificate installation.

3

Auto-renewal

# Test renewal
sudo certbot renew --dry-run

# Add to crontab for auto-renewal
sudo crontab -e
# Add: 0 12 * * * /usr/bin/certbot renew --quiet

Monitoring and Logging

Log Management

Configure log rotation in /etc/logrotate.d/managex:

/var/www/managex/server/logs/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    create 644 www-data www-data
    postrotate
        /usr/bin/pm2 reloadLogs
    endscript
}

Health Monitoring

Set up monitoring with tools like:

  • PM2 Monitoring: Built-in process monitoring with pm2 monit
  • Uptime Robot: External uptime monitoring
  • New Relic: Application performance monitoring
  • DataDog: Infrastructure monitoring
  • Grafana + Prometheus: Custom monitoring dashboards

Backup Strategy

#!/bin/bash
# Database backup script
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/backups/managex"
DB_NAME="managex_db"
DB_USER="managex_user"
DB_PASSWORD="your_password"

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup database
mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $BACKUP_DIR/db_backup_$DATE.sql

# Compress backup
gzip $BACKUP_DIR/db_backup_$DATE.sql

# Backup uploads
tar -czf $BACKUP_DIR/uploads_backup_$DATE.tar.gz /var/www/managex/server/public/uploads/

# Keep only last 30 days of backups
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete

# Optional: Upload to cloud storage (AWS S3, etc.)
# aws s3 cp $BACKUP_DIR/db_backup_$DATE.sql.gz s3://your-bucket/backups/

Automated Backups

Add the backup script to crontab to run daily:

# Edit crontab
sudo crontab -e

# Add daily backup at 2 AM
0 2 * * * /path/to/backup-script.sh

Security Hardening

Server Security

  • Keep the system and packages updated regularly
  • Configure firewall (UFW or iptables) to allow only necessary ports
  • Disable root login and use SSH keys for authentication
  • Install fail2ban for brute force protection
  • Use non-standard ports for SSH (if applicable)
  • Enable automatic security updates

Application Security

  • Use environment variables for all sensitive data
  • Implement proper input validation and sanitization
  • Use HTTPS everywhere (enforce SSL/TLS)
  • Set secure HTTP headers (XSS protection, content type, etc.)
  • Regular security audits and dependency updates
  • Implement rate limiting on API endpoints
  • Use strong JWT secrets and rotate them periodically

Database Security

  • Use strong, unique passwords for database users
  • Limit database user privileges (principle of least privilege)
  • Enable SSL for database connections in production
  • Regular security updates for MySQL
  • Monitor database access logs
  • Restrict database access to localhost only
  • Regular database backups with encryption

Performance Optimization

Node.js Optimization

Setting Value Description
NODE_ENV production Enables production optimizations
UV_THREADPOOL_SIZE 128 Increases thread pool size for better I/O performance
NODE_OPTIONS --max-old-space-size=4096 Increases memory limit to 4GB

Database Optimization

  • Add appropriate indexes on frequently queried columns
  • Optimize slow queries using EXPLAIN
  • Use connection pooling (Sequelize handles this automatically)
  • Regular database maintenance (ANALYZE, OPTIMIZE)
  • Monitor query performance and optimize as needed
  • Consider read replicas for high-traffic scenarios

Caching Strategy

  • Implement Redis for session storage (optional)
  • Use CDN for static assets if serving large files
  • Enable browser caching with proper cache headers
  • Database query result caching for frequently accessed data
  • Implement application-level caching for expensive operations

Deployment Checklist

Pre-deployment

  • ✅ Test all functionality in staging environment
  • ✅ Configure production environment variables
  • ✅ Set up SSL certificates
  • ✅ Configure web server (Nginx/Apache)
  • ✅ Set up database with proper security
  • ✅ Configure monitoring and logging
  • ✅ Set up automated backup procedures
  • ✅ Configure firewall rules

Deployment

  • ✅ Deploy application code to production server
  • ✅ Run database migrations (npm run db:migrate)
  • ✅ Seed initial data if needed (npm run demo with IS_DEMO=0)
  • ✅ Start application services (PM2 or systemd)
  • ✅ Configure load balancer (if applicable)
  • ✅ Test all endpoints and functionality
  • ✅ Verify SSL certificate is working
  • ✅ Test backup and restore procedures

Post-deployment

  • ✅ Monitor application performance and resource usage
  • ✅ Check error logs regularly
  • ✅ Verify backup procedures are working
  • ✅ Test failover and disaster recovery procedures
  • ✅ Document any custom configurations
  • ✅ Set up alerting for critical issues
  • ✅ Schedule regular security updates
  • ✅ Monitor database performance and optimize as needed