# Production Deployment Automation ⚠️ **WICHTIG:** Diese Dokumentation ist veraltet. **Für aktuelle Deployment-Automation siehe:** - **[deployment/ansible/](../../deployment/ansible/)** - Aktuelle Ansible-Playbooks - **[deployment/DEPLOYMENT_COMMANDS.md](../../deployment/DEPLOYMENT_COMMANDS.md)** - Command-Referenz - **[deployment/CODE_CHANGE_WORKFLOW.md](../../deployment/CODE_CHANGE_WORKFLOW.md)** - Workflow-Dokumentation --- **Historische Dokumentation (veraltet):** Comprehensive guide to automated production deployment scripts for the Custom PHP Framework. ## Overview The framework includes three main automation scripts for production operations: 1. **`production-deploy.sh`** - Full deployment automation (initial, update, rollback) 2. **`health-check.sh`** - Comprehensive health monitoring 3. **`backup.sh`** - Automated backup system All scripts are located in `scripts/` directory and designed for Docker-based production deployments. ## Production Deployment Script **Location**: `scripts/production-deploy.sh` ### Usage ```bash # Initial deployment (first time) ./scripts/production-deploy.sh initial # Update deployment (zero-downtime rolling update) ./scripts/production-deploy.sh update # Rollback to previous version ./scripts/production-deploy.sh rollback ``` ### Initial Deployment First-time production setup with complete environment initialization: ```bash # Prerequisites: # 1. .env.production configured with VAULT_ENCRYPTION_KEY # 2. docker-compose.production.yml present # 3. Server meets hardware requirements (8GB RAM, 4 CPUs) ./scripts/production-deploy.sh initial ``` **What it does**: 1. ✅ Checks prerequisites (Docker, Compose, configuration files) 2. ✅ Verifies VAULT_ENCRYPTION_KEY is configured 3. ✅ Builds Docker images with production optimizations 4. ✅ Starts all services (web, php, db, redis, queue-worker, certbot) 5. ✅ Waits for services to be ready (20s) 6. ✅ Runs database migrations 7. ✅ Initializes SSL certificates via PHP console command 8. ✅ Verifies Vault is accessible 9. ✅ Runs health checks with retries (30 attempts) 10. ✅ Displays deployment summary **Output Example**: ``` [12:34:56] 🚀 Starting initial production deployment... [12:34:56] Checking prerequisites... ✅ Prerequisites check passed [12:35:10] Building Docker images... ✅ Docker images built [12:36:00] Starting Docker services... [12:36:20] Running database migrations... ✅ Database migrations completed [12:36:30] Initializing SSL certificates... ✅ SSL certificate initialized [12:36:40] Running health checks... ✅ Health check passed ======================================== Deployment Summary ======================================== 📋 Mode: initial ⏰ Timestamp: 2024-10-25 12:37:00 📁 Project: /home/michael/dev/michaelschiemer 💾 Backup: (none - initial deployment) 🐳 Docker Services: NAME STATUS web Up (healthy) php Up (healthy) db Up (healthy) redis Up (healthy) queue-worker Up (2 replicas) certbot Up 🔒 Security Checks: [ ] APP_ENV=production in .env.production [ ] APP_DEBUG=false in .env.production [ ] VAULT_ENCRYPTION_KEY configured [ ] ADMIN_ALLOWED_IPS configured [ ] SSL certificates valid ✅ 🎉 Initial deployment completed successfully! ``` ### Update Deployment (Zero-Downtime) Rolling update with automatic backup and health checks: ```bash ./scripts/production-deploy.sh update ``` **What it does**: 1. ✅ Checks prerequisites 2. ✅ **Creates full backup** (database, .env, storage) 3. ✅ Pulls latest images (if using registry) 4. ✅ Builds new Docker images 5. ✅ Runs database migrations 6. ✅ **Rolling restart** with minimal downtime: - PHP-FPM first (10s wait) - Web server next (5s wait) - Queue workers last (graceful shutdown via 60s grace period) 7. ✅ Runs health checks 8. ✅ Cleans up old Docker images 9. ✅ Displays summary **Zero-Downtime Strategy**: - **PHP-FPM** restarted first while old web server still serves requests - **Web Server** restarted after PHP is ready - **Queue Workers** restarted last with 60s graceful shutdown for jobs to complete - **Health checks** verify each step before proceeding **Automatic Rollback on Failure**: If any step fails, the script automatically rolls back to the backup: ```bash ❌ Health check failed after 30 attempts [12:40:00] Cleaning up after error... ⚠️ Rolling back to previous version... [12:40:10] Restoring from backup: /backups/backup_20241025_123456 ✅ Database restored ✅ .env restored ✅ Storage restored ✅ Backup restored successfully ``` ### Rollback Deployment Restore from latest backup: ```bash ./scripts/production-deploy.sh rollback ``` **What it does**: 1. ✅ Finds latest backup 2. ✅ Prompts for confirmation 3. ✅ Restores database from backup 4. ✅ Restores .env configuration 5. ✅ Restores storage directory 6. ✅ Restarts all services 7. ✅ Runs health checks **Interactive Confirmation**: ``` ⏪ Starting rollback... ⚠️ Rolling back to: /backups/backup_20241025_123456 Continue? (yes/no): yes [12:45:00] Restoring from backup... ✅ Database restored ✅ .env restored ✅ Storage restored ✅ Backup restored successfully ✅ Health check passed ✅ 🎉 Rollback completed successfully! ``` ### Backup Strategy Backups are created automatically during update deployments: **Backup Location**: `../backups/backup_YYYYMMDD_HHMMSS_*` **Backup Contents**: - `backup_YYYYMMDD_HHMMSS_database.sql.gz` - PostgreSQL database dump - `backup_YYYYMMDD_HHMMSS_env` - .env configuration - `backup_YYYYMMDD_HHMMSS_storage.tar.gz` - Storage directory (logs, cache, queue) **Retention Policy**: Last 5 backups are retained, older backups are automatically cleaned up. ### Error Handling The script includes comprehensive error handling: ```bash # Automatic cleanup on error trap cleanup_on_error ERR cleanup_on_error() { log "Cleaning up after error..." if [[ -d "$BACKUP_PATH" ]]; then warning "Rolling back to previous version..." restore_backup "$BACKUP_PATH" fi } ``` **Common Errors**: 1. **Missing VAULT_ENCRYPTION_KEY**: ``` ❌ VAULT_ENCRYPTION_KEY not configured in .env.production ``` **Fix**: Generate key with `docker exec php php console.php vault:generate-key` 2. **Prerequisites not met**: ``` ❌ Docker is not installed ``` **Fix**: Install Docker and Docker Compose 3. **Health check failed**: ``` ❌ Health check failed after 30 attempts ``` **Fix**: Check logs with `docker compose logs -f --tail=100` --- ## Health Check Script **Location**: `scripts/health-check.sh` ### Usage ```bash # Basic health check ./scripts/health-check.sh # Verbose output ./scripts/health-check.sh --verbose # JSON output (for monitoring systems) ./scripts/health-check.sh --json ``` ### Health Check Components The script performs 12 comprehensive health checks: 1. **Docker Daemon** - Verifies Docker is running 2. **Docker Services** - Checks all 5 services (web, php, db, redis, queue-worker) 3. **Web Response** - HTTP response from Nginx (3 retries) 4. **Health Endpoint** - `/health` endpoint availability 5. **Database** - PostgreSQL connectivity via `pg_isready` 6. **Redis** - Redis ping command 7. **SSL Certificate** - Certificate validity via PHP console 8. **Vault** - Vault accessibility check 9. **Disk Space** - Disk usage monitoring (warn >80%, critical >90%) 10. **Memory** - System memory usage (warn >80%, critical >90%) 11. **Queue Workers** - Verify 2 workers running 12. **Recent Errors** - Log analysis for error frequency ### Output Format **Standard Output**: ``` [12:50:00] 🔍 Starting production health check... [12:50:01] Checking Docker daemon... ✅ Docker daemon is running [12:50:02] Checking Docker Compose services... ✅ All Docker services are running [12:50:03] Checking web server response... ✅ Web server is responding [12:50:04] Checking /health endpoint... ✅ Health endpoint is responding [12:50:05] Checking database connectivity... ✅ Database is accepting connections [12:50:06] Checking Redis connectivity... ✅ Redis is responding [12:50:07] Checking SSL certificate... ✅ SSL certificate is valid [12:50:08] Checking Vault connectivity... ✅ Vault is accessible [12:50:09] Checking disk space... ✅ Disk space usage: 45% [12:50:10] Checking memory usage... ✅ Memory usage: 62% [12:50:11] Checking queue workers... ✅ Queue workers: 2 running [12:50:12] Checking recent errors in logs... ✅ Recent errors: 2 (last 1000 lines) ======================================== Production Health Check Summary ======================================== 📊 Health Status: ✅ Healthy: 12 ⚠️ Warnings: 0 ❌ Unhealthy: 0 Overall Status: HEALTHY ✅ 🎉 All critical systems are operational ======================================== ``` **JSON Output** (for monitoring systems): ```json { "timestamp": "2024-10-25T12:50:12+00:00", "overall_status": "healthy", "checks": { "docker": "healthy", "service_web": "healthy", "service_php": "healthy", "service_db": "healthy", "service_redis": "healthy", "service_queue-worker": "healthy", "web_response": "healthy", "health_endpoint": "healthy", "database": "healthy", "redis": "healthy", "ssl": "healthy", "vault": "healthy", "disk_space": "healthy", "memory": "healthy", "queue_workers": "healthy", "recent_errors": "healthy" } } ``` ### Verbose Mode Provides additional details: ```bash ./scripts/health-check.sh --verbose ``` **Additional Information**: - Active database connections - Redis memory usage - Full SSL certificate status - Detailed error log excerpt ### Exit Codes - **0** - All checks healthy - **1** - One or more critical checks failed ### Integration with Monitoring **Cron Job** (every 5 minutes): ```cron */5 * * * * /path/to/scripts/health-check.sh --json > /var/log/health-check.json ``` **Alerting Integration**: ```bash # Send alert if unhealthy if ! ./scripts/health-check.sh &>/dev/null; then ./scripts/send-alert.sh "Production health check failed" fi ``` --- ## Backup Script **Location**: `scripts/backup.sh` ### Usage ```bash # Full backup (database + vault + files) ./scripts/backup.sh --full # Database only ./scripts/backup.sh --database-only # Vault only ./scripts/backup.sh --vault-only # Encrypted backup (GPG) ./scripts/backup.sh --full --encrypt ``` ### Backup Components 1. **Database Backup** - PostgreSQL dump via `pg_dump` - Gzipped for compression - Optional GPG encryption 2. **Vault Backup** - Vault secrets table (`vault_secrets`) - Vault audit table (`vault_audit`) - **Encryption highly recommended** 3. **Environment Configuration** - `.env.production` file backup - Contains sensitive configuration 4. **Storage Directory** - Logs, cache, queue, discovery, uploads - Tar.gz compression 5. **Uploaded Files** - `public/uploads/` directory - Media and user-uploaded content ### Backup Process ```bash ./scripts/backup.sh --full --encrypt ``` **Output**: ``` [13:00:00] 🔐 Starting production backup (type: full)... [13:00:01] Preparing backup directory... ✅ Backup directory created: /backups/20241025_130000 [13:00:02] Backing up database... ✅ Database backup created: database.sql.gz (245M) [13:00:05] Encrypting /backups/20241025_130000/database.sql.gz... ✅ File encrypted: database.sql.gz.gpg [13:00:10] Backing up Vault secrets... ✅ Vault backup created: vault_secrets.sql.gz (2.3M) ⚠️ Vault backup is not encrypted - consider using --encrypt [13:00:12] Backing up environment configuration... ✅ Environment configuration backed up [13:00:13] Backing up storage directory... ✅ Storage backup created: storage.tar.gz (120M) [13:00:18] Backing up uploaded files... ✅ Uploads backup created: uploads.tar.gz (1.5G) [13:00:45] Creating backup manifest... ✅ Backup manifest created [13:00:46] Verifying backup integrity... ✓ database.sql.gz.gpg is valid ✓ storage.tar.gz is valid ✓ uploads.tar.gz is valid ✅ All backup files verified successfully [13:00:47] Cleaning up old backups... ✅ Old backups cleaned up (kept last 7 days) ======================================== Backup Summary ======================================== 📋 Backup Type: full ⏰ Timestamp: 2024-10-25 13:00:47 📁 Location: /backups/20241025_130000 🔒 Encrypted: true 📦 Backup Contents: 1.5G uploads.tar.gz 245M database.sql.gz.gpg 120M storage.tar.gz 2.3M vault_secrets.sql.gz 💾 Total Size: 1.9G 📝 Restoration Commands: Database: gpg -d database.sql.gz.gpg | gunzip | docker compose exec -T db psql -U postgres michaelschiemer_prod Vault: gunzip -c vault_secrets.sql.gz | docker compose exec -T db psql -U postgres michaelschiemer_prod Storage: tar -xzf storage.tar.gz -C /path/to/project ======================================== ✅ 🎉 Backup completed successfully! ``` ### Backup Encryption GPG symmetric encryption (AES-256): ```bash ./scripts/backup.sh --full --encrypt ``` **What gets encrypted**: - Database dumps - Vault backups - Environment configuration **Decryption**: ```bash # Decrypt file gpg -d database.sql.gz.gpg > database.sql.gz # Restore database gunzip -c database.sql.gz | docker compose exec -T db psql -U postgres michaelschiemer_prod ``` **Encryption Password**: - Prompted during backup - **Store securely** in password manager - Required for restoration ### Backup Retention **Automatic Cleanup**: - Backups older than 7 days are automatically deleted - Keeps last 7 days of backups - Configurable in script **Manual Cleanup**: ```bash # Remove specific backup rm -rf /backups/20241025_130000 # Remove all backups older than 30 days find /backups -type d -name "20*" -mtime +30 -exec rm -rf {} \; ``` ### Backup Verification All backups are automatically verified: **Verification Checks**: - Gzip integrity (`gzip -t`) - Tar.gz integrity (`tar -tzf`) - File completeness **Failed Verification**: ``` ✗ database.sql.gz is corrupted ❌ Some backup files are corrupted ``` ### Restoration Procedures **Full System Restoration**: 1. **Restore Database**: ```bash cd /backups/20241025_130000 # If encrypted gpg -d database.sql.gz.gpg | gunzip | docker compose exec -T db psql -U postgres michaelschiemer_prod # If not encrypted gunzip -c database.sql.gz | docker compose exec -T db psql -U postgres michaelschiemer_prod ``` 2. **Restore Vault**: ```bash gunzip -c vault_secrets.sql.gz | docker compose exec -T db psql -U postgres michaelschiemer_prod ``` 3. **Restore Environment**: ```bash cp env.production /path/to/project/.env.production ``` 4. **Restore Storage**: ```bash tar -xzf storage.tar.gz -C /path/to/project ``` 5. **Restore Uploads**: ```bash tar -xzf uploads.tar.gz -C /path/to/project/public ``` 6. **Restart Services**: ```bash docker compose -f docker-compose.yml -f docker-compose.production.yml --env-file .env.production restart ``` ### Automated Backup Schedule **Recommended Cron Jobs**: ```cron # Daily full backup at 2 AM (encrypted) 0 2 * * * /path/to/scripts/backup.sh --full --encrypt >> /var/log/backup.log 2>&1 # Hourly database backup 0 * * * * /path/to/scripts/backup.sh --database-only >> /var/log/backup.log 2>&1 # Weekly Vault backup (encrypted) 0 3 * * 0 /path/to/scripts/backup.sh --vault-only --encrypt >> /var/log/backup.log 2>&1 ``` **Backup Monitoring**: ```bash # Check if backup succeeded if ! tail -1 /var/log/backup.log | grep -q "completed successfully"; then ./scripts/send-alert.sh "Backup failed" fi ``` --- ## Integration with Production Workflow ### Complete Production Deployment Workflow **Step 1: Initial Setup** ```bash # Prerequisites 1. Configure .env.production with all required values 2. Generate VAULT_ENCRYPTION_KEY: docker exec php php console.php vault:generate-key 3. Update ADMIN_ALLOWED_IPS for IP-based access control 4. Configure SSL_DOMAIN and SSL_EMAIL for Let's Encrypt # Deploy ./scripts/production-deploy.sh initial ``` **Step 2: Verify Deployment** ```bash # Run health check ./scripts/health-check.sh --verbose # Check logs docker compose logs -f --tail=100 # Test application curl -H "User-Agent: Mozilla/5.0" https://your-domain.com/health ``` **Step 3: Create Initial Backup** ```bash # Full encrypted backup ./scripts/backup.sh --full --encrypt ``` **Step 4: Regular Updates** ```bash # Zero-downtime update ./scripts/production-deploy.sh update # Verify health ./scripts/health-check.sh ``` ### Automated Operations **Daily Operations Cron**: ```cron # Health check every 5 minutes */5 * * * * /path/to/scripts/health-check.sh --json > /var/log/health-check.json # Full backup daily at 2 AM 0 2 * * * /path/to/scripts/backup.sh --full --encrypt >> /var/log/backup.log 2>&1 # Cleanup old logs at 3 AM 0 3 * * * find /path/to/project/storage/logs -name "*.log" -mtime +30 -delete ``` ### Monitoring Integration **Prometheus Metrics** (from health-check.sh JSON output): ```yaml # prometheus.yml scrape_configs: - job_name: 'health-check' static_configs: - targets: ['localhost:9090'] metrics_path: '/metrics' file_sd_configs: - files: - '/var/log/health-check.json' ``` **Grafana Dashboard**: - Service status panels - Resource usage graphs - Error rate trends - SSL certificate expiry countdown --- ## Troubleshooting ### Deployment Script Issues **Problem**: Prerequisites check fails ``` ❌ .env.production not found ``` **Solution**: Copy `.env.example` to `.env.production` and configure all values **Problem**: Health check fails ``` ❌ Health check failed after 30 attempts ``` **Solutions**: 1. Check Docker logs: `docker compose logs -f php` 2. Verify all services are up: `docker compose ps` 3. Check firewall: `sudo ufw status` 4. Verify DNS: `dig your-domain.com` **Problem**: SSL initialization fails ``` ❌ SSL initialization failed ``` **Solutions**: 1. Verify DNS A record points to server 2. Check ports 80/443 are open 3. Verify SSL_DOMAIN in .env.production 4. Check Certbot logs: `docker compose logs certbot` ### Health Check Script Issues **Problem**: Web response check fails ``` ❌ Web server is not responding ``` **Solutions**: 1. Check Nginx status: `docker compose ps web` 2. Check Nginx logs: `docker compose logs web` 3. Verify SSL certificates: `docker compose exec php php console.php ssl:status` **Problem**: Database check fails ``` ❌ Database is not accepting connections ``` **Solutions**: 1. Check PostgreSQL status: `docker compose ps db` 2. Check PostgreSQL logs: `docker compose logs db` 3. Verify database credentials in .env.production ### Backup Script Issues **Problem**: Database backup fails ``` ❌ Database backup failed ``` **Solutions**: 1. Check database container: `docker compose ps db` 2. Verify database credentials 3. Check disk space: `df -h` **Problem**: GPG encryption fails ``` ⚠️ GPG not installed - skipping encryption ``` **Solution**: Install GPG: `sudo apt install gnupg` **Problem**: Backup verification fails ``` ✗ database.sql.gz is corrupted ``` **Solutions**: 1. Run backup again 2. Check disk space 3. Verify database health --- ## Best Practices ### Deployment Best Practices 1. **Always test in staging first** 2. **Run health check before deployment** 3. **Create backup before updates** 4. **Monitor logs during deployment** 5. **Verify health after deployment** 6. **Have rollback plan ready** 7. **Document all configuration changes** ### Backup Best Practices 1. **Encrypt Vault backups** (always) 2. **Store backups off-site** (AWS S3, external server) 3. **Test restoration regularly** (monthly) 4. **Verify backup integrity** (automated) 5. **Monitor backup size growth** 6. **Rotate encryption passwords** (quarterly) 7. **Keep multiple backup copies** (3-2-1 rule: 3 copies, 2 media types, 1 off-site) ### Monitoring Best Practices 1. **Run health checks every 5 minutes** 2. **Alert on critical failures** (email, Slack, PagerDuty) 3. **Monitor resource usage trends** 4. **Track deployment success rate** 5. **Review logs daily** 6. **Set up uptime monitoring** (UptimeRobot, Pingdom) 7. **Document incident responses** --- ## See Also - **Prerequisites**: `docs/deployment/production-prerequisites.md` - **Environment Configuration**: `docs/deployment/env-production-template.md` - **Docker Compose Production**: `docs/deployment/docker-compose-production.md` - **Database Migrations**: `docs/deployment/database-migration-strategy.md` - **SSL Setup**: `docs/deployment/ssl-setup.md` - **Secrets Management**: `docs/deployment/secrets-management.md` - **Logging Configuration**: `docs/deployment/logging-configuration.md`