- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
11 KiB
Production Deployment - Quick Start Guide
Goal: Get the application running in production in under 30 minutes.
This is a simplified, essential-steps-only guide. For comprehensive documentation, see:
Prerequisites
- Ubuntu 22.04+ server with root access
- Domain name pointing to server IP
- Port 80 and 443 open in firewall
Step 1: Initial Server Setup (10 minutes)
# SSH into server
ssh root@your-server.com
# Update system
apt update && apt upgrade -y
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
# Install Docker Compose
apt install docker-compose-plugin -y
# Install certbot for SSL
apt install certbot -y
# Create application user
useradd -m -s /bin/bash appuser
usermod -aG docker appuser
Step 2: SSL Certificate (5 minutes)
# Create webroot directory
mkdir -p /var/www/certbot
# Get SSL certificate
certbot certonly --webroot \
-w /var/www/certbot \
-d yourdomain.com \
--email your-email@example.com \
--agree-tos \
--non-interactive
# Verify certificates
ls -la /etc/letsencrypt/live/yourdomain.com/
Expected output: fullchain.pem and privkey.pem files
Step 3: Clone Application (2 minutes)
# Switch to app user
su - appuser
# Clone repository
git clone https://github.com/your-org/your-app.git /home/appuser/app
cd /home/appuser/app
# Checkout production branch
git checkout main
Step 4: Generate Secrets (3 minutes)
# Generate Vault encryption key
php scripts/deployment/generate-vault-key.php
# Save output - YOU MUST STORE THIS SECURELY!
# Example output: vault_key_abc123def456...
⚠️ CRITICAL: Store this key in your password manager. You cannot recover it if lost.
Step 5: Create Environment File (5 minutes)
# Copy example
cp .env.example .env.production
# Edit configuration
nano .env.production
Minimal required configuration:
# Application
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
# Database
DB_HOST=database
DB_PORT=3306
DB_NAME=app_production
DB_USER=app_user
DB_PASS=GENERATE_STRONG_PASSWORD_HERE
# Vault
VAULT_ENCRYPTION_KEY=YOUR_GENERATED_KEY_FROM_STEP_4
# Logging
LOG_PATH=/var/log/app
LOG_LEVEL=INFO
# Admin Access
ADMIN_ALLOWED_IPS=YOUR.SERVER.IP,127.0.0.1
Generate strong passwords:
# Generate DB password
openssl rand -base64 32
# Generate JWT secret
openssl rand -base64 64
Step 6: Build and Start (3 minutes)
# Build containers
docker compose -f docker-compose.production.yml build
# Start containers
docker compose -f docker-compose.production.yml up -d
# Check status
docker compose -f docker-compose.production.yml ps
Expected output: All containers should be "Up"
Step 7: Initialize Database (2 minutes)
# Run migrations
docker compose -f docker-compose.production.yml exec php php console.php db:migrate
# Verify migration status
docker compose -f docker-compose.production.yml exec php php console.php db:status
Step 8: Verify Health (1 minute)
# Check health endpoint
curl http://localhost/health/summary
# Expected output (healthy):
{
"timestamp": "2025-01-15T10:00:00+00:00",
"overall_status": "healthy",
"overall_healthy": true,
"summary": {
"total_checks": 8,
"healthy": 8,
"warning": 0,
"unhealthy": 0
}
}
If unhealthy, check logs:
docker compose -f docker-compose.production.yml logs php
Step 9: Configure Nginx Reverse Proxy
# Exit to root user
exit
# Create Nginx config
nano /etc/nginx/sites-available/app
Nginx configuration:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
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_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
location / {
proxy_pass http://localhost:8080;
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;
}
location /health {
proxy_pass http://localhost:8080/health;
access_log off;
}
}
Enable and restart:
# Enable site
ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
# Test configuration
nginx -t
# Restart Nginx
systemctl restart nginx
Step 10: Final Verification
# Test HTTPS endpoint
curl -f https://yourdomain.com/health/summary
# Test detailed health
curl -f https://yourdomain.com/health/detailed
# Test metrics (should be accessible)
curl -f https://yourdomain.com/metrics
✅ Success criteria:
- All curl commands return 200 OK
- No SSL certificate warnings
- Health endpoint shows all checks healthy
Post-Deployment Tasks
Setup Automatic Certificate Renewal
# Test renewal
certbot renew --dry-run
# Certbot automatically creates cron job, verify:
systemctl status certbot.timer
Setup Log Rotation
# Create logrotate config
nano /etc/logrotate.d/app
/var/log/app/*.log {
daily
rotate 14
compress
delaycompress
notifempty
missingok
create 0644 appuser appuser
sharedscripts
postrotate
docker compose -f /home/appuser/app/docker-compose.production.yml exec php php console.php cache:clear > /dev/null 2>&1 || true
endscript
}
Setup Monitoring (Optional but Recommended)
# Install monitoring stack
cd /home/appuser/app
docker compose -f docker-compose.monitoring.yml up -d
# Access Grafana
# URL: http://your-server:3000
# Default credentials: admin/admin
Setup Backups
# Create backup script
nano /home/appuser/backup-production.sh
#!/bin/bash
set -e
BACKUP_DIR="/opt/backups"
DATE=$(date +%Y%m%d_%H%M%S)
# Backup database
docker compose -f /home/appuser/app/docker-compose.production.yml \
exec -T database mysqldump -u app_user -p${DB_PASS} app_production | \
gzip > ${BACKUP_DIR}/db_${DATE}.sql.gz
# Backup Vault
tar -czf ${BACKUP_DIR}/vault_${DATE}.tar.gz /opt/vault
# Keep only last 7 days
find ${BACKUP_DIR} -name "*.gz" -mtime +7 -delete
echo "Backup completed: ${DATE}"
# Make executable
chmod +x /home/appuser/backup-production.sh
# Add to crontab (daily at 2 AM)
crontab -e
Add line:
0 2 * * * /home/appuser/backup-production.sh >> /var/log/backup.log 2>&1
Troubleshooting
Container won't start
# Check logs
docker compose -f docker-compose.production.yml logs php
# Common issues:
# - Wrong database credentials → Check .env.production
# - Port already in use → Check: netstat -tulpn | grep 8080
# - Permission issues → Run: chown -R appuser:appuser /home/appuser/app
Health checks failing
# Check specific health check
curl http://localhost/health/category/database
# Common issues:
# - Database not migrated → Run: php console.php db:migrate
# - Cache not writable → Check: ls -la /var/cache/app
# - Queue not running → Check: docker compose ps
SSL certificate issues
# Check certificate validity
openssl x509 -in /etc/letsencrypt/live/yourdomain.com/fullchain.pem -noout -dates
# Renew certificate
certbot renew --force-renewal
# Restart Nginx
systemctl restart nginx
Application errors
# Check application logs
docker compose -f docker-compose.production.yml logs -f php
# Check Nginx logs
tail -f /var/log/nginx/error.log
# Check system logs
journalctl -u nginx -f
Security Hardening (Do This After Deployment)
1. Firewall Configuration
# Install UFW
apt install ufw -y
# Allow SSH
ufw allow 22/tcp
# Allow HTTP/HTTPS
ufw allow 80/tcp
ufw allow 443/tcp
# Enable firewall
ufw enable
2. SSH Key-Only Authentication
# Generate SSH key on local machine
ssh-keygen -t ed25519 -C "your-email@example.com"
# Copy to server
ssh-copy-id root@your-server.com
# Disable password authentication
nano /etc/ssh/sshd_config
Set:
PasswordAuthentication no
PermitRootLogin prohibit-password
Restart SSH:
systemctl restart sshd
3. Fail2Ban
# Install fail2ban
apt install fail2ban -y
# Create jail for Nginx
nano /etc/fail2ban/jail.d/nginx-limit.conf
[nginx-limit-req]
enabled = true
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime = 3600
# Restart fail2ban
systemctl restart fail2ban
Deployment Updates (Ongoing)
For deploying updates after initial setup:
# SSH to server
ssh appuser@your-server.com
# Navigate to app
cd /home/appuser/app
# Pull latest code
git pull origin main
# Rebuild containers
docker compose -f docker-compose.production.yml build
# Run migrations (if any)
docker compose -f docker-compose.production.yml exec php php console.php db:migrate
# Restart containers
docker compose -f docker-compose.production.yml up -d
# Verify health
curl -f http://localhost/health/summary
For zero-downtime deployments, use the automated script:
./scripts/deployment/blue-green-deploy.sh
Getting Help
If you encounter issues not covered in this quick start:
-
Check detailed documentation:
-
Check application logs:
docker compose -f docker-compose.production.yml logs -f -
Check health endpoints:
curl http://localhost/health/detailed | jq -
Check metrics:
curl http://localhost/metrics
Success Checklist
✅ Before considering deployment complete:
- SSL certificate installed and valid
- Application accessible via HTTPS
- All health checks passing (green)
- Database migrations applied successfully
- Logs being written to
/var/log/app - Automatic certificate renewal configured
- Backup script running daily
- Firewall configured (ports 22, 80, 443 only)
- SSH key-only authentication enabled
- Fail2Ban installed and monitoring
- Monitoring stack running (optional)
- Team has access to Vault encryption key
- Database backup verified and restorable
Next Steps
After successful deployment:
- Setup Monitoring Alerts: Configure Prometheus alerting rules
- Performance Tuning: Review metrics and optimize based on actual traffic
- Security Audit: Run security scan with tools like OWASP ZAP
- Documentation: Document any custom configuration changes
- Team Training: Ensure team knows deployment and rollback procedures
- Disaster Recovery: Test backup restoration procedure
Estimated Timeline
- Initial deployment (following this guide): 30 minutes
- Security hardening: 15 minutes
- Monitoring setup: 20 minutes
- Total time to production: ~1 hour
You're ready for production! 🚀
For questions or issues, refer to the comprehensive guides linked throughout this document.