Files
michaelschiemer/docs/deployment/QUICKSTART.md
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- 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.
2025-10-25 19:18:37 +02:00

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
}
# 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:

  1. Check detailed documentation:

  2. Check application logs:

    docker compose -f docker-compose.production.yml logs -f
    
  3. Check health endpoints:

    curl http://localhost/health/detailed | jq
    
  4. 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:

  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.