- 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.
600 lines
11 KiB
Markdown
600 lines
11 KiB
Markdown
# 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:
|
|
- [Complete Deployment Workflow](DEPLOYMENT_WORKFLOW.md)
|
|
- [Production Deployment Guide](PRODUCTION_DEPLOYMENT.md)
|
|
- [Ansible Deployment](ANSIBLE_DEPLOYMENT.md)
|
|
|
|
---
|
|
|
|
## 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)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# Copy example
|
|
cp .env.example .env.production
|
|
|
|
# Edit configuration
|
|
nano .env.production
|
|
```
|
|
|
|
**Minimal required configuration**:
|
|
|
|
```env
|
|
# 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**:
|
|
```bash
|
|
# Generate DB password
|
|
openssl rand -base64 32
|
|
|
|
# Generate JWT secret
|
|
openssl rand -base64 64
|
|
```
|
|
|
|
---
|
|
|
|
## Step 6: Build and Start (3 minutes)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
docker compose -f docker-compose.production.yml logs php
|
|
```
|
|
|
|
---
|
|
|
|
## Step 9: Configure Nginx Reverse Proxy
|
|
|
|
```bash
|
|
# Exit to root user
|
|
exit
|
|
|
|
# Create Nginx config
|
|
nano /etc/nginx/sites-available/app
|
|
```
|
|
|
|
**Nginx configuration**:
|
|
|
|
```nginx
|
|
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**:
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# Test renewal
|
|
certbot renew --dry-run
|
|
|
|
# Certbot automatically creates cron job, verify:
|
|
systemctl status certbot.timer
|
|
```
|
|
|
|
### Setup Log Rotation
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# Create backup script
|
|
nano /home/appuser/backup-production.sh
|
|
```
|
|
|
|
```bash
|
|
#!/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}"
|
|
```
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
systemctl restart sshd
|
|
```
|
|
|
|
### 3. Fail2Ban
|
|
|
|
```bash
|
|
# Install fail2ban
|
|
apt install fail2ban -y
|
|
|
|
# Create jail for Nginx
|
|
nano /etc/fail2ban/jail.d/nginx-limit.conf
|
|
```
|
|
|
|
```ini
|
|
[nginx-limit-req]
|
|
enabled = true
|
|
filter = nginx-limit-req
|
|
logpath = /var/log/nginx/error.log
|
|
maxretry = 10
|
|
findtime = 60
|
|
bantime = 3600
|
|
```
|
|
|
|
```bash
|
|
# Restart fail2ban
|
|
systemctl restart fail2ban
|
|
```
|
|
|
|
---
|
|
|
|
## Deployment Updates (Ongoing)
|
|
|
|
For deploying updates after initial setup:
|
|
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
./scripts/deployment/blue-green-deploy.sh
|
|
```
|
|
|
|
---
|
|
|
|
## Getting Help
|
|
|
|
If you encounter issues not covered in this quick start:
|
|
|
|
1. **Check detailed documentation**:
|
|
- [Complete Deployment Workflow](DEPLOYMENT_WORKFLOW.md)
|
|
- [Production Deployment Guide](PRODUCTION_DEPLOYMENT.md)
|
|
- [Troubleshooting Guide](PRODUCTION_DEPLOYMENT.md#troubleshooting)
|
|
|
|
2. **Check application logs**:
|
|
```bash
|
|
docker compose -f docker-compose.production.yml logs -f
|
|
```
|
|
|
|
3. **Check health endpoints**:
|
|
```bash
|
|
curl http://localhost/health/detailed | jq
|
|
```
|
|
|
|
4. **Check metrics**:
|
|
```bash
|
|
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:
|
|
|
|
1. **Setup Monitoring Alerts**: Configure Prometheus alerting rules
|
|
2. **Performance Tuning**: Review metrics and optimize based on actual traffic
|
|
3. **Security Audit**: Run security scan with tools like OWASP ZAP
|
|
4. **Documentation**: Document any custom configuration changes
|
|
5. **Team Training**: Ensure team knows deployment and rollback procedures
|
|
6. **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.
|