404 lines
6.8 KiB
Markdown
404 lines
6.8 KiB
Markdown
|
|
---
|
||
|
|
description: How to deploy the backend to production
|
||
|
|
---
|
||
|
|
|
||
|
|
# Deployment Workflow
|
||
|
|
|
||
|
|
Follow these steps to deploy the E-Learning Platform backend to production.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Prerequisites
|
||
|
|
|
||
|
|
- Production server with Node.js 18+
|
||
|
|
- PostgreSQL database
|
||
|
|
- MinIO/S3 storage
|
||
|
|
- Domain name and SSL certificate
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 1: Prepare Production Server
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Update system
|
||
|
|
sudo apt update && sudo apt upgrade -y
|
||
|
|
|
||
|
|
# Install Node.js 18
|
||
|
|
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||
|
|
sudo apt install -y nodejs
|
||
|
|
|
||
|
|
# Install PM2
|
||
|
|
sudo npm install -g pm2
|
||
|
|
|
||
|
|
# Install nginx
|
||
|
|
sudo apt install -y nginx
|
||
|
|
|
||
|
|
# Install certbot for SSL
|
||
|
|
sudo apt install -y certbot python3-certbot-nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 2: Clone Repository
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create app directory
|
||
|
|
sudo mkdir -p /var/www/elearning-backend
|
||
|
|
sudo chown $USER:$USER /var/www/elearning-backend
|
||
|
|
|
||
|
|
# Clone repository
|
||
|
|
cd /var/www/elearning-backend
|
||
|
|
git clone <repository-url> .
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 3: Install Dependencies
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npm ci --production
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 4: Setup Environment Variables
|
||
|
|
|
||
|
|
Create `.env` file:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Application
|
||
|
|
NODE_ENV=production
|
||
|
|
PORT=4000
|
||
|
|
APP_URL=https://api.elearning.com
|
||
|
|
|
||
|
|
# Database
|
||
|
|
DATABASE_URL=postgresql://user:password@db-host:5432/elearning_prod
|
||
|
|
|
||
|
|
# MinIO/S3
|
||
|
|
S3_ENDPOINT=https://s3.elearning.com
|
||
|
|
S3_ACCESS_KEY=<access-key>
|
||
|
|
S3_SECRET_KEY=<secret-key>
|
||
|
|
S3_BUCKET_COURSES=courses
|
||
|
|
S3_BUCKET_VIDEOS=videos
|
||
|
|
S3_BUCKET_DOCUMENTS=documents
|
||
|
|
S3_BUCKET_IMAGES=images
|
||
|
|
S3_BUCKET_ATTACHMENTS=attachments
|
||
|
|
|
||
|
|
# JWT
|
||
|
|
JWT_SECRET=<strong-random-secret>
|
||
|
|
JWT_EXPIRES_IN=24h
|
||
|
|
|
||
|
|
# Email
|
||
|
|
SMTP_HOST=smtp.gmail.com
|
||
|
|
SMTP_PORT=587
|
||
|
|
SMTP_USER=<email>
|
||
|
|
SMTP_PASSWORD=<password>
|
||
|
|
SMTP_FROM=noreply@elearning.com
|
||
|
|
|
||
|
|
# CORS
|
||
|
|
CORS_ORIGIN=https://elearning.com,https://admin.elearning.com
|
||
|
|
|
||
|
|
# Rate Limiting
|
||
|
|
RATE_LIMIT_WINDOW_MS=900000
|
||
|
|
RATE_LIMIT_MAX_REQUESTS=100
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 5: Run Database Migrations
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npx prisma migrate deploy
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 6: Setup PM2
|
||
|
|
|
||
|
|
Create `ecosystem.config.js`:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
module.exports = {
|
||
|
|
apps: [{
|
||
|
|
name: 'elearning-backend',
|
||
|
|
script: './src/server.js',
|
||
|
|
instances: 'max',
|
||
|
|
exec_mode: 'cluster',
|
||
|
|
env: {
|
||
|
|
NODE_ENV: 'production'
|
||
|
|
},
|
||
|
|
error_file: './logs/err.log',
|
||
|
|
out_file: './logs/out.log',
|
||
|
|
log_file: './logs/combined.log',
|
||
|
|
time: true
|
||
|
|
}]
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
Start application:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
pm2 start ecosystem.config.js
|
||
|
|
pm2 save
|
||
|
|
pm2 startup
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 7: Configure Nginx
|
||
|
|
|
||
|
|
Create `/etc/nginx/sites-available/elearning-backend`:
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
upstream backend {
|
||
|
|
server localhost:4000;
|
||
|
|
}
|
||
|
|
|
||
|
|
server {
|
||
|
|
listen 80;
|
||
|
|
server_name api.elearning.com;
|
||
|
|
|
||
|
|
# Redirect to HTTPS
|
||
|
|
return 301 https://$server_name$request_uri;
|
||
|
|
}
|
||
|
|
|
||
|
|
server {
|
||
|
|
listen 443 ssl http2;
|
||
|
|
server_name api.elearning.com;
|
||
|
|
|
||
|
|
# SSL Configuration
|
||
|
|
ssl_certificate /etc/letsencrypt/live/api.elearning.com/fullchain.pem;
|
||
|
|
ssl_certificate_key /etc/letsencrypt/live/api.elearning.com/privkey.pem;
|
||
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||
|
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||
|
|
|
||
|
|
# Security Headers
|
||
|
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||
|
|
add_header X-Content-Type-Options "nosniff" always;
|
||
|
|
add_header X-XSS-Protection "1; mode=block" always;
|
||
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||
|
|
|
||
|
|
# Logging
|
||
|
|
access_log /var/log/nginx/elearning-backend-access.log;
|
||
|
|
error_log /var/log/nginx/elearning-backend-error.log;
|
||
|
|
|
||
|
|
# File Upload Size
|
||
|
|
client_max_body_size 500M;
|
||
|
|
|
||
|
|
location / {
|
||
|
|
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;
|
||
|
|
|
||
|
|
# Timeouts
|
||
|
|
proxy_connect_timeout 600s;
|
||
|
|
proxy_send_timeout 600s;
|
||
|
|
proxy_read_timeout 600s;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Enable site:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sudo ln -s /etc/nginx/sites-available/elearning-backend /etc/nginx/sites-enabled/
|
||
|
|
sudo nginx -t
|
||
|
|
sudo systemctl restart nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 8: Setup SSL Certificate
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sudo certbot --nginx -d api.elearning.com
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 9: Setup Monitoring
|
||
|
|
|
||
|
|
### PM2 Monitoring
|
||
|
|
|
||
|
|
```bash
|
||
|
|
pm2 install pm2-logrotate
|
||
|
|
pm2 set pm2-logrotate:max_size 10M
|
||
|
|
pm2 set pm2-logrotate:retain 30
|
||
|
|
```
|
||
|
|
|
||
|
|
### Health Check Endpoint
|
||
|
|
|
||
|
|
Add to your app:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
app.get('/health', (req, res) => {
|
||
|
|
res.status(200).json({
|
||
|
|
status: 'ok',
|
||
|
|
timestamp: new Date().toISOString(),
|
||
|
|
uptime: process.uptime()
|
||
|
|
});
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 10: Setup Backup
|
||
|
|
|
||
|
|
Create backup script `/opt/scripts/backup-db.sh`:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
#!/bin/bash
|
||
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||
|
|
BACKUP_DIR="/var/backups/elearning"
|
||
|
|
DB_NAME="elearning_prod"
|
||
|
|
|
||
|
|
mkdir -p $BACKUP_DIR
|
||
|
|
|
||
|
|
# Backup database
|
||
|
|
pg_dump $DB_NAME | gzip > $BACKUP_DIR/db_$DATE.sql.gz
|
||
|
|
|
||
|
|
# Keep only last 7 days
|
||
|
|
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +7 -delete
|
||
|
|
|
||
|
|
echo "Backup completed: db_$DATE.sql.gz"
|
||
|
|
```
|
||
|
|
|
||
|
|
Add to crontab:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Daily backup at 2 AM
|
||
|
|
0 2 * * * /opt/scripts/backup-db.sh
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Step 11: Verify Deployment
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Check PM2 status
|
||
|
|
pm2 status
|
||
|
|
|
||
|
|
# Check logs
|
||
|
|
pm2 logs elearning-backend --lines 50
|
||
|
|
|
||
|
|
# Test health endpoint
|
||
|
|
curl https://api.elearning.com/health
|
||
|
|
|
||
|
|
# Test API
|
||
|
|
curl https://api.elearning.com/api/courses
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Update Deployment
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Pull latest code
|
||
|
|
cd /var/www/elearning-backend
|
||
|
|
git pull origin main
|
||
|
|
|
||
|
|
# Install dependencies
|
||
|
|
npm ci --production
|
||
|
|
|
||
|
|
# Run migrations
|
||
|
|
npx prisma migrate deploy
|
||
|
|
|
||
|
|
# Restart application
|
||
|
|
pm2 restart elearning-backend
|
||
|
|
|
||
|
|
# Check status
|
||
|
|
pm2 status
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Rollback
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Revert to previous commit
|
||
|
|
git reset --hard HEAD~1
|
||
|
|
|
||
|
|
# Reinstall dependencies
|
||
|
|
npm ci --production
|
||
|
|
|
||
|
|
# Rollback migration (if needed)
|
||
|
|
npx prisma migrate resolve --rolled-back <migration-name>
|
||
|
|
|
||
|
|
# Restart
|
||
|
|
pm2 restart elearning-backend
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Checklist
|
||
|
|
|
||
|
|
- [ ] Production server setup
|
||
|
|
- [ ] Repository cloned
|
||
|
|
- [ ] Dependencies installed
|
||
|
|
- [ ] Environment variables configured
|
||
|
|
- [ ] Database migrated
|
||
|
|
- [ ] PM2 configured and running
|
||
|
|
- [ ] Nginx configured
|
||
|
|
- [ ] SSL certificate installed
|
||
|
|
- [ ] Monitoring setup
|
||
|
|
- [ ] Backup script configured
|
||
|
|
- [ ] Health check working
|
||
|
|
- [ ] API endpoints tested
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Security Checklist
|
||
|
|
|
||
|
|
- [ ] Strong JWT secret
|
||
|
|
- [ ] Database credentials secured
|
||
|
|
- [ ] CORS configured correctly
|
||
|
|
- [ ] Rate limiting enabled
|
||
|
|
- [ ] SSL/TLS enabled
|
||
|
|
- [ ] Security headers configured
|
||
|
|
- [ ] File upload limits set
|
||
|
|
- [ ] Environment variables not in git
|
||
|
|
- [ ] Firewall configured
|
||
|
|
- [ ] SSH key-based authentication
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Monitoring
|
||
|
|
|
||
|
|
### PM2 Commands
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# View logs
|
||
|
|
pm2 logs
|
||
|
|
|
||
|
|
# Monitor resources
|
||
|
|
pm2 monit
|
||
|
|
|
||
|
|
# Restart app
|
||
|
|
pm2 restart elearning-backend
|
||
|
|
|
||
|
|
# Stop app
|
||
|
|
pm2 stop elearning-backend
|
||
|
|
|
||
|
|
# Delete app
|
||
|
|
pm2 delete elearning-backend
|
||
|
|
```
|
||
|
|
|
||
|
|
### Check System Resources
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# CPU and Memory
|
||
|
|
htop
|
||
|
|
|
||
|
|
# Disk usage
|
||
|
|
df -h
|
||
|
|
|
||
|
|
# Network connections
|
||
|
|
netstat -tulpn
|
||
|
|
```
|