# Deployment Guide This guide covers various deployment scenarios for EasyStream, from development to production environments. ## Quick Start (Docker) ### Prerequisites - Docker 20.10+ - Docker Compose 2.0+ - 4GB+ RAM - 20GB+ storage ### Basic Deployment ```bash # Clone repository git clone cd easystream # Configure environment cp .env.example .env # Edit .env with your settings # Start services docker-compose up -d --build # Verify deployment curl http://localhost:8083 ``` ## Production Deployment ### System Requirements #### Minimum Requirements - **CPU**: 2 cores - **RAM**: 4GB - **Storage**: 50GB SSD - **Network**: 100Mbps #### Recommended Requirements - **CPU**: 4+ cores - **RAM**: 8GB+ - **Storage**: 200GB+ SSD - **Network**: 1Gbps ### Environment Configuration #### Environment Variables ```bash # Application MAIN_URL=https://your-domain.com DEBUG_MODE=false ENVIRONMENT=production # Database DB_HOST=db DB_NAME=easystream DB_USER=easystream DB_PASS=secure_password_here # Security SESSION_SECURE=true CSRF_PROTECTION=enabled RATE_LIMITING=enabled # Storage UPLOAD_MAX_SIZE=2G STORAGE_DRIVER=local # For S3: STORAGE_DRIVER=s3 # AWS_ACCESS_KEY_ID=your_key # AWS_SECRET_ACCESS_KEY=your_secret # AWS_DEFAULT_REGION=us-east-1 # AWS_BUCKET=your-bucket # Email MAIL_DRIVER=smtp MAIL_HOST=smtp.your-provider.com MAIL_PORT=587 MAIL_USERNAME=your_email@domain.com MAIL_PASSWORD=your_password MAIL_ENCRYPTION=tls # Live Streaming SRS_RTMP_PORT=1935 SRS_HTTP_PORT=8080 HLS_SEGMENT_DURATION=10 HLS_WINDOW_SIZE=60 # Monitoring LOG_LEVEL=warning LOG_DRIVER=file # For centralized logging: LOG_DRIVER=syslog ``` ### Docker Production Setup #### Production Docker Compose ```yaml # docker-compose.prod.yml version: '3.8' services: php: build: context: . dockerfile: Dockerfile.php target: production environment: - ENVIRONMENT=production - DEBUG_MODE=false volumes: - ./f_data:/var/www/html/f_data - uploads:/var/www/html/f_data/uploads - hls:/var/www/html/hls restart: unless-stopped depends_on: - db - redis caddy: image: caddy:2-alpine ports: - "80:80" - "443:443" volumes: - ./Caddyfile.prod:/etc/caddy/Caddyfile - caddy_data:/data - caddy_config:/config - hls:/srv/hls:ro restart: unless-stopped depends_on: - php db: image: mariadb:10.11 environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASS} MYSQL_DATABASE: ${DB_NAME} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_PASS} volumes: - db_data:/var/lib/mysql - ./deploy/mysql.cnf:/etc/mysql/conf.d/custom.cnf restart: unless-stopped command: --innodb-buffer-pool-size=1G redis: image: redis:7-alpine volumes: - redis_data:/data restart: unless-stopped command: redis-server --appendonly yes srs: image: ossrs/srs:5 ports: - "1935:1935" - "8080:8080" volumes: - ./deploy/srs.prod.conf:/usr/local/srs/conf/srs.conf - hls:/usr/local/srs/objs/nginx/html/hls - recordings:/usr/local/srs/objs/nginx/html/rec restart: unless-stopped cron: build: context: . dockerfile: Dockerfile.cron volumes: - ./f_data:/var/www/html/f_data - uploads:/var/www/html/f_data/uploads restart: unless-stopped depends_on: - db - redis volumes: db_data: redis_data: caddy_data: caddy_config: uploads: hls: recordings: ``` #### Production Caddyfile ```caddyfile # Caddyfile.prod { email your-email@domain.com admin off } your-domain.com { # Security headers header { Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" X-Content-Type-Options "nosniff" X-Frame-Options "DENY" X-XSS-Protection "1; mode=block" Referrer-Policy "strict-origin-when-cross-origin" Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; media-src 'self' blob:; connect-src 'self' wss:" } # Rate limiting rate_limit { zone static { key {remote_host} events 100 window 1m } zone api { key {remote_host} events 1000 window 1h } } # HLS streaming handle /hls/* { root * /srv file_server { precompressed gzip br } header Cache-Control "public, max-age=10" } # Static assets handle /f_scripts/* /f_templates/* { root * /var/www/html file_server { precompressed gzip br } header Cache-Control "public, max-age=31536000" } # API endpoints handle /api/* { rate_limit api reverse_proxy php:9000 { transport fastcgi { split .php } } } # Main application handle { root * /var/www/html php_fastcgi php:9000 file_server } # Logging log { output file /var/log/caddy/access.log { roll_size 100mb roll_keep 5 } format json } } ``` ### Manual Installation #### Server Setup (Ubuntu 22.04) ```bash # Update system sudo apt update && sudo apt upgrade -y # Install PHP 8.2 sudo add-apt-repository ppa:ondrej/php -y sudo apt update sudo apt install -y php8.2 php8.2-fpm php8.2-mysql php8.2-gd php8.2-curl \ php8.2-mbstring php8.2-xml php8.2-zip php8.2-bcmath php8.2-intl # Install MariaDB sudo apt install -y mariadb-server sudo mysql_secure_installation # Install Nginx sudo apt install -y nginx # Install FFmpeg sudo apt install -y ffmpeg # Install SRS wget https://github.com/ossrs/srs/releases/download/v5.0.156/srs-server-5.0.156-ubuntu20-amd64.deb sudo dpkg -i srs-server-5.0.156-ubuntu20-amd64.deb ``` #### Database Setup ```sql -- Create database and user CREATE DATABASE easystream CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'easystream'@'localhost' IDENTIFIED BY 'secure_password'; GRANT ALL PRIVILEGES ON easystream.* TO 'easystream'@'localhost'; FLUSH PRIVILEGES; -- Import schema mysql -u easystream -p easystream < __install/easystream.sql ``` #### Nginx Configuration ```nginx # /etc/nginx/sites-available/easystream server { listen 80; server_name your-domain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.com; root /var/www/easystream; index index.php index.html; # SSL Configuration ssl_certificate /path/to/certificate.crt; ssl_certificate_key /path/to/private.key; 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 Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" 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; # Rate limiting limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=general:10m rate=1r/s; # HLS streaming location /hls/ { alias /var/srs/hls/; add_header Cache-Control "no-cache, no-store, must-revalidate"; add_header Access-Control-Allow-Origin "*"; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range"; } # API endpoints location /api/ { limit_req zone=api burst=20 nodelay; try_files $uri $uri/ /index.php?$query_string; } # PHP processing location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } # Static files location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; } # Security location ~ /\. { deny all; } location ~ /(f_data|__install|tests)/ { deny all; } } ``` #### PHP-FPM Configuration ```ini ; /etc/php/8.2/fpm/pool.d/easystream.conf [easystream] user = www-data group = www-data listen = /var/run/php/php8.2-fpm-easystream.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 pm = dynamic pm.max_children = 50 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 35 pm.max_requests = 1000 ; PHP settings php_admin_value[upload_max_filesize] = 2G php_admin_value[post_max_size] = 2G php_admin_value[max_execution_time] = 300 php_admin_value[memory_limit] = 512M ``` ### Cloud Deployment #### AWS Deployment ```bash # Using AWS ECS with Fargate aws ecs create-cluster --cluster-name easystream-prod # Create task definition aws ecs register-task-definition --cli-input-json file://ecs-task-definition.json # Create service aws ecs create-service \ --cluster easystream-prod \ --service-name easystream-web \ --task-definition easystream:1 \ --desired-count 2 \ --launch-type FARGATE \ --network-configuration "awsvpcConfiguration={subnets=[subnet-12345],securityGroups=[sg-12345],assignPublicIp=ENABLED}" ``` #### Google Cloud Platform ```bash # Deploy to Cloud Run gcloud run deploy easystream \ --image gcr.io/PROJECT_ID/easystream \ --platform managed \ --region us-central1 \ --allow-unauthenticated \ --memory 2Gi \ --cpu 2 \ --max-instances 10 ``` #### DigitalOcean App Platform ```yaml # .do/app.yaml name: easystream services: - name: web source_dir: / github: repo: your-username/easystream branch: main run_command: php-fpm environment_slug: php instance_count: 2 instance_size_slug: professional-xs envs: - key: ENVIRONMENT value: production - key: DB_HOST value: ${db.HOSTNAME} - key: DB_NAME value: ${db.DATABASE} - key: DB_USER value: ${db.USERNAME} - key: DB_PASS value: ${db.PASSWORD} databases: - name: db engine: MYSQL version: "8" size: db-s-1vcpu-1gb ``` ### SSL/TLS Configuration #### Let's Encrypt with Certbot ```bash # Install Certbot sudo apt install -y certbot python3-certbot-nginx # Obtain certificate sudo certbot --nginx -d your-domain.com # Auto-renewal sudo crontab -e # Add: 0 12 * * * /usr/bin/certbot renew --quiet ``` #### Cloudflare SSL ```bash # Configure Cloudflare origin certificates # Download origin certificate and key # Update Nginx/Caddy configuration with certificate paths ``` ### Monitoring and Logging #### System Monitoring ```bash # Install monitoring tools sudo apt install -y htop iotop nethogs # Install Prometheus Node Exporter wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz tar xvfz node_exporter-1.6.1.linux-amd64.tar.gz sudo cp node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/ sudo useradd --no-create-home --shell /bin/false node_exporter sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter ``` #### Log Management ```bash # Configure log rotation sudo tee /etc/logrotate.d/easystream << EOF /var/www/easystream/f_data/logs/*.log { daily missingok rotate 30 compress delaycompress notifempty create 644 www-data www-data } EOF ``` ### Backup Strategy #### Database Backup ```bash #!/bin/bash # backup-db.sh DATE=$(date +%Y%m%d_%H%M%S) BACKUP_DIR="/backups/database" mkdir -p $BACKUP_DIR mysqldump -u easystream -p easystream | gzip > $BACKUP_DIR/easystream_$DATE.sql.gz # Keep only last 30 days find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete ``` #### File Backup ```bash #!/bin/bash # backup-files.sh DATE=$(date +%Y%m%d_%H%M%S) BACKUP_DIR="/backups/files" SOURCE_DIR="/var/www/easystream/f_data" mkdir -p $BACKUP_DIR tar -czf $BACKUP_DIR/files_$DATE.tar.gz -C $SOURCE_DIR . # Keep only last 7 days find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete ``` ### Performance Optimization #### Database Optimization ```sql -- MySQL/MariaDB configuration [mysqld] innodb_buffer_pool_size = 2G innodb_log_file_size = 256M innodb_flush_log_at_trx_commit = 2 query_cache_size = 128M query_cache_type = 1 max_connections = 200 ``` #### PHP Optimization ```ini ; php.ini optimizations opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.revalidate_freq=2 opcache.fast_shutdown=1 realpath_cache_size=4096K realpath_cache_ttl=600 ``` #### CDN Configuration ```bash # Configure CloudFlare or AWS CloudFront # Cache static assets: images, videos, CSS, JS # Set appropriate cache headers # Enable compression (gzip/brotli) ``` ### Security Hardening #### Firewall Configuration ```bash # UFW firewall rules sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow ssh sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 1935/tcp # RTMP sudo ufw enable ``` #### Fail2Ban Setup ```bash # Install Fail2Ban sudo apt install -y fail2ban # Configure jail sudo tee /etc/fail2ban/jail.local << EOF [DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 [nginx-http-auth] enabled = true filter = nginx-http-auth logpath = /var/log/nginx/error.log [nginx-limit-req] enabled = true filter = nginx-limit-req logpath = /var/log/nginx/error.log maxretry = 10 EOF sudo systemctl restart fail2ban ``` ### Troubleshooting #### Common Issues 1. **502 Bad Gateway**: Check PHP-FPM status and configuration 2. **Database Connection**: Verify credentials and network connectivity 3. **File Permissions**: Ensure www-data has proper permissions 4. **Memory Issues**: Increase PHP memory limit and server RAM 5. **Streaming Issues**: Check SRS configuration and network ports #### Debug Commands ```bash # Check service status sudo systemctl status nginx php8.2-fpm mariadb # View logs sudo tail -f /var/log/nginx/error.log sudo tail -f /var/www/easystream/f_data/logs/error_$(date +%Y-%m-%d).log # Test database connection mysql -u easystream -p -h localhost easystream # Check disk space df -h # Monitor processes htop ``` ### Maintenance #### Regular Maintenance Tasks ```bash #!/bin/bash # maintenance.sh - Run weekly # Update system packages sudo apt update && sudo apt upgrade -y # Clean up old logs find /var/www/easystream/f_data/logs -name "*.log" -mtime +30 -delete # Optimize database mysql -u easystream -p -e "OPTIMIZE TABLE easystream.videos, easystream.users, easystream.comments;" # Clear application cache rm -rf /var/www/easystream/f_data/cache/* # Restart services sudo systemctl restart php8.2-fpm nginx ``` #### Health Checks ```bash #!/bin/bash # health-check.sh - Run every 5 minutes # Check web server if ! curl -f http://localhost > /dev/null 2>&1; then echo "Web server down" | mail -s "EasyStream Alert" admin@domain.com fi # Check database if ! mysql -u easystream -p -e "SELECT 1" > /dev/null 2>&1; then echo "Database down" | mail -s "EasyStream Alert" admin@domain.com fi # Check disk space DISK_USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//') if [ $DISK_USAGE -gt 90 ]; then echo "Disk usage: ${DISK_USAGE}%" | mail -s "EasyStream Alert" admin@domain.com fi ```