chore: Update deployment configuration and documentation
- Update Gitea configuration (remove DEFAULT_ACTIONS_URL) - Fix deployment documentation - Update Ansible playbooks - Clean up deprecated files - Add new deployment scripts and templates
This commit is contained in:
@@ -1,5 +1,15 @@
|
||||
# Ansible-Based Deployment
|
||||
|
||||
⚠️ **WICHTIG:** Diese Dokumentation ist veraltet.
|
||||
|
||||
**Für aktuelle Ansible-Deployment-Dokumentation siehe:**
|
||||
- **[deployment/ansible/README.md](../../deployment/ansible/README.md)** - Aktuelle Ansible-Dokumentation
|
||||
- **[deployment/DEPLOYMENT_COMMANDS.md](../../deployment/DEPLOYMENT_COMMANDS.md)** - Command-Referenz
|
||||
|
||||
---
|
||||
|
||||
**Historische Dokumentation (veraltet):**
|
||||
|
||||
Fortgeschrittenes Deployment mit Ansible für Multi-Server Orchestrierung und Infrastructure as Code.
|
||||
|
||||
## Übersicht
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# 🚀 Production Deployment Guide
|
||||
|
||||
## Schneller Deployment-Workflow
|
||||
|
||||
### 1. Environment Setup (KRITISCH)
|
||||
```bash
|
||||
# Kopiere .env Template
|
||||
cp .env.production .env
|
||||
|
||||
# Setze ALLE CHANGE_ME Werte:
|
||||
nano .env
|
||||
```
|
||||
|
||||
**WICHTIG:** Folgende Werte MÜSSEN gesetzt werden:
|
||||
- `DB_PASSWORD` - Starkes Datenbankpasswort
|
||||
- `SHOPIFY_WEBHOOK_SECRET` - Nur wenn Shopify verwendet wird
|
||||
- `RAPIDMAIL_USERNAME/PASSWORD` - Nur wenn RapidMail verwendet wird
|
||||
|
||||
### 2. Database Setup
|
||||
```bash
|
||||
# 1. Datenbank erstellen
|
||||
mysql -u root -p
|
||||
CREATE DATABASE production_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE USER 'production_user'@'localhost' IDENTIFIED BY 'DEIN_PASSWORT';
|
||||
GRANT ALL PRIVILEGES ON production_db.* TO 'production_user'@'localhost';
|
||||
FLUSH PRIVILEGES;
|
||||
EXIT;
|
||||
|
||||
# 2. Migration ausführen
|
||||
mysql -u production_user -p production_db < migrations/2024_01_01_create_meta_entries_table.sql
|
||||
```
|
||||
|
||||
### 3. Assets Build (falls Frontend verwendet)
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 4. Basic Health Check
|
||||
```bash
|
||||
# Server starten und testen
|
||||
php -S localhost:8000 -t public/
|
||||
curl http://localhost:8000/
|
||||
```
|
||||
|
||||
## Sicherheits-Checklist ✅
|
||||
|
||||
- [x] Keine hardcoded Secrets im Code
|
||||
- [x] Starke Datenbankpasswörter
|
||||
- [x] Production .env Template erstellt
|
||||
- [x] Environment-basierte Konfiguration
|
||||
|
||||
## Next Steps (Optional)
|
||||
|
||||
1. **SSL Setup** - Let's Encrypt oder eigene Zertifikate
|
||||
2. **Webserver Config** - nginx/Apache Konfiguration
|
||||
3. **Process Manager** - PM2, systemd oder supervisor
|
||||
4. **Monitoring** - Log-Aggregation und Error-Tracking
|
||||
5. **Backup Strategy** - Automatische DB-Backups
|
||||
|
||||
## Rollback Strategy
|
||||
|
||||
Bei Problemen:
|
||||
```bash
|
||||
# 1. Alte Version aktivieren
|
||||
git checkout previous-version
|
||||
|
||||
# 2. Assets neu bauen (falls nötig)
|
||||
npm run build
|
||||
|
||||
# 3. Cache leeren
|
||||
# (abhängig von Setup)
|
||||
```
|
||||
@@ -1,374 +0,0 @@
|
||||
# Production Deployment Checklist
|
||||
|
||||
**Print this and check off items as you complete them.**
|
||||
|
||||
---
|
||||
|
||||
## Pre-Deployment Checklist
|
||||
|
||||
### Infrastructure
|
||||
|
||||
- [ ] Server meets requirements (Ubuntu 22.04+, 4GB RAM, 40GB disk)
|
||||
- [ ] Domain name configured and pointing to server IP
|
||||
- [ ] DNS propagation verified (nslookup yourdomain.com)
|
||||
- [ ] Firewall rules configured (ports 22, 80, 443 open)
|
||||
- [ ] SSH access to server confirmed
|
||||
- [ ] Root or sudo access verified
|
||||
|
||||
### Security
|
||||
|
||||
- [ ] SSH key pair generated
|
||||
- [ ] SSH key added to server
|
||||
- [ ] Vault encryption key generated
|
||||
- [ ] Vault key stored in password manager
|
||||
- [ ] Database passwords generated (32+ characters)
|
||||
- [ ] JWT secrets generated (64+ characters)
|
||||
- [ ] Admin allowed IPs list prepared
|
||||
- [ ] SSL certificate email address ready
|
||||
|
||||
### Code
|
||||
|
||||
- [ ] Application repository accessible
|
||||
- [ ] Production branch exists and tested
|
||||
- [ ] All tests passing locally
|
||||
- [ ] Database migrations reviewed
|
||||
- [ ] .env.example up to date
|
||||
- [ ] Dependencies reviewed (composer.json, package.json)
|
||||
|
||||
---
|
||||
|
||||
## Deployment Steps Checklist
|
||||
|
||||
### Step 1: Server Setup
|
||||
|
||||
- [ ] SSH into server
|
||||
- [ ] System updated (apt update && upgrade)
|
||||
- [ ] Docker installed
|
||||
- [ ] Docker Compose installed
|
||||
- [ ] Certbot installed
|
||||
- [ ] Application user created
|
||||
- [ ] Application user added to docker group
|
||||
- [ ] Directory structure created (/var/www/app, /var/log/app, /opt/vault)
|
||||
|
||||
### Step 2: SSL Certificate
|
||||
|
||||
- [ ] Webroot directory created (/var/www/certbot)
|
||||
- [ ] Certbot certificate obtained
|
||||
- [ ] Certificate files verified (fullchain.pem, privkey.pem)
|
||||
- [ ] Certificate expiration date checked (>30 days)
|
||||
- [ ] Auto-renewal tested (certbot renew --dry-run)
|
||||
|
||||
### Step 3: Application Code
|
||||
|
||||
- [ ] Repository cloned to /home/appuser/app
|
||||
- [ ] Production branch checked out
|
||||
- [ ] Git configured (user.name, user.email)
|
||||
- [ ] File permissions set correctly (chown -R appuser:appuser)
|
||||
|
||||
### Step 4: Environment Configuration
|
||||
|
||||
- [ ] .env.production created from .env.example
|
||||
- [ ] APP_ENV set to "production"
|
||||
- [ ] APP_DEBUG set to "false"
|
||||
- [ ] APP_URL configured with domain
|
||||
- [ ] Database credentials configured
|
||||
- [ ] VAULT_ENCRYPTION_KEY added
|
||||
- [ ] LOG_PATH configured
|
||||
- [ ] ADMIN_ALLOWED_IPS configured
|
||||
- [ ] All required environment variables set
|
||||
- [ ] Sensitive values NOT committed to git
|
||||
|
||||
### Step 5: Docker Containers
|
||||
|
||||
- [ ] docker-compose.production.yml reviewed
|
||||
- [ ] Containers built (docker compose build)
|
||||
- [ ] Containers started (docker compose up -d)
|
||||
- [ ] All containers running (docker compose ps)
|
||||
- [ ] Container logs checked for errors
|
||||
- [ ] Container networking verified
|
||||
|
||||
### Step 6: Database
|
||||
|
||||
- [ ] Database container healthy
|
||||
- [ ] Database migrations applied (php console.php db:migrate)
|
||||
- [ ] Migration status verified (php console.php db:status)
|
||||
- [ ] Database backup created
|
||||
- [ ] Database connection tested
|
||||
|
||||
### Step 7: Health Checks
|
||||
|
||||
- [ ] Health endpoint accessible (curl http://localhost/health/summary)
|
||||
- [ ] All health checks passing (overall_healthy: true)
|
||||
- [ ] Database health check: healthy
|
||||
- [ ] Cache health check: healthy
|
||||
- [ ] Queue health check: healthy
|
||||
- [ ] Filesystem health check: healthy
|
||||
- [ ] SSL health check: healthy
|
||||
- [ ] Detailed health endpoint tested
|
||||
|
||||
### Step 8: Nginx Configuration
|
||||
|
||||
- [ ] Nginx installed
|
||||
- [ ] Site configuration created (/etc/nginx/sites-available/app)
|
||||
- [ ] SSL certificates paths correct in config
|
||||
- [ ] Proxy settings configured
|
||||
- [ ] Site enabled (symlink in sites-enabled)
|
||||
- [ ] Nginx configuration tested (nginx -t)
|
||||
- [ ] Nginx restarted
|
||||
- [ ] HTTPS redirect working (http → https)
|
||||
|
||||
### Step 9: Application Verification
|
||||
|
||||
- [ ] HTTPS endpoint accessible (https://yourdomain.com)
|
||||
- [ ] SSL certificate valid (no browser warnings)
|
||||
- [ ] Homepage loads correctly
|
||||
- [ ] API endpoints responding
|
||||
- [ ] Authentication working
|
||||
- [ ] Admin panel accessible (from allowed IPs)
|
||||
- [ ] File uploads working
|
||||
- [ ] Background jobs processing
|
||||
- [ ] Email sending configured
|
||||
|
||||
### Step 10: Monitoring
|
||||
|
||||
- [ ] Metrics endpoint accessible (/metrics)
|
||||
- [ ] Prometheus metrics valid format
|
||||
- [ ] Health checks integrated with monitoring
|
||||
- [ ] Log files being created (/var/log/app/)
|
||||
- [ ] Log rotation configured
|
||||
- [ ] Disk space monitored
|
||||
- [ ] Memory usage monitored
|
||||
- [ ] CPU usage monitored
|
||||
|
||||
---
|
||||
|
||||
## Post-Deployment Checklist
|
||||
|
||||
### Security Hardening
|
||||
|
||||
- [ ] UFW firewall enabled
|
||||
- [ ] Only required ports open (22, 80, 443)
|
||||
- [ ] SSH password authentication disabled
|
||||
- [ ] Root login disabled via SSH
|
||||
- [ ] Fail2Ban installed and configured
|
||||
- [ ] Security headers verified (X-Frame-Options, CSP, etc.)
|
||||
- [ ] OWASP security scan performed
|
||||
- [ ] SSL Labs test passed (A+ rating)
|
||||
|
||||
### Backups
|
||||
|
||||
- [ ] Database backup script created
|
||||
- [ ] Vault backup script created
|
||||
- [ ] Backup directory created (/opt/backups)
|
||||
- [ ] Backup cron job configured
|
||||
- [ ] Backup restoration tested
|
||||
- [ ] Backup retention policy configured (7 days)
|
||||
- [ ] Off-site backup configured (optional but recommended)
|
||||
|
||||
### Monitoring & Alerts
|
||||
|
||||
- [ ] Grafana installed (optional)
|
||||
- [ ] Prometheus configured (optional)
|
||||
- [ ] Alert rules configured
|
||||
- [ ] Email notifications configured
|
||||
- [ ] Disk space alerts set (>90% usage)
|
||||
- [ ] Memory alerts set (>90% usage)
|
||||
- [ ] Health check alerts set
|
||||
- [ ] SSL expiration alerts set (30 days)
|
||||
|
||||
### Documentation
|
||||
|
||||
- [ ] Deployment procedure documented
|
||||
- [ ] Server credentials documented (in secure location)
|
||||
- [ ] Vault encryption key documented (in secure location)
|
||||
- [ ] Database backup location documented
|
||||
- [ ] Rollback procedure documented
|
||||
- [ ] Team access granted and documented
|
||||
- [ ] On-call rotation documented
|
||||
|
||||
### Performance
|
||||
|
||||
- [ ] Performance baseline established
|
||||
- [ ] Slow query log enabled
|
||||
- [ ] Cache hit rate monitored
|
||||
- [ ] Response time benchmarked
|
||||
- [ ] Load testing performed
|
||||
- [ ] Database indexes optimized
|
||||
- [ ] Asset compression enabled (gzip)
|
||||
- [ ] CDN configured (optional)
|
||||
|
||||
### Compliance & Legal
|
||||
|
||||
- [ ] Privacy policy deployed
|
||||
- [ ] Terms of service deployed
|
||||
- [ ] Cookie consent implemented (if EU traffic)
|
||||
- [ ] GDPR compliance verified (if EU traffic)
|
||||
- [ ] Data retention policies documented
|
||||
- [ ] Incident response plan documented
|
||||
|
||||
---
|
||||
|
||||
## Rollback Checklist
|
||||
|
||||
**Use this if deployment fails and you need to rollback:**
|
||||
|
||||
### Immediate Rollback
|
||||
|
||||
- [ ] Stop new containers: `docker compose down`
|
||||
- [ ] Start old containers: `docker compose -f docker-compose.old.yml up -d`
|
||||
- [ ] Verify health: `curl http://localhost/health/summary`
|
||||
- [ ] Rollback database migrations: `php console.php db:rollback`
|
||||
- [ ] Clear cache: `php console.php cache:clear`
|
||||
- [ ] Verify application functionality
|
||||
- [ ] Notify team of rollback
|
||||
|
||||
### Post-Rollback
|
||||
|
||||
- [ ] Document rollback reason
|
||||
- [ ] Identify root cause
|
||||
- [ ] Create fix for issue
|
||||
- [ ] Test fix in staging
|
||||
- [ ] Plan next deployment attempt
|
||||
- [ ] Update deployment procedure if needed
|
||||
|
||||
---
|
||||
|
||||
## Weekly Maintenance Checklist
|
||||
|
||||
**Perform these checks weekly:**
|
||||
|
||||
- [ ] Review application logs for errors
|
||||
- [ ] Check disk space (should be <80%)
|
||||
- [ ] Review health check status
|
||||
- [ ] Verify backups running successfully
|
||||
- [ ] Check SSL certificate expiration (>30 days remaining)
|
||||
- [ ] Review security logs (fail2ban)
|
||||
- [ ] Check for system updates
|
||||
- [ ] Review performance metrics
|
||||
- [ ] Test backup restoration (monthly)
|
||||
|
||||
---
|
||||
|
||||
## Monthly Maintenance Checklist
|
||||
|
||||
**Perform these checks monthly:**
|
||||
|
||||
- [ ] Apply system security updates
|
||||
- [ ] Review and update dependencies (composer update, npm update)
|
||||
- [ ] Rotate secrets (API keys, tokens) if required
|
||||
- [ ] Review and archive old logs
|
||||
- [ ] Perform security audit
|
||||
- [ ] Review and update documentation
|
||||
- [ ] Test disaster recovery procedure
|
||||
- [ ] Review and optimize database performance
|
||||
- [ ] Review monitoring alerts effectiveness
|
||||
- [ ] Update deployment runbook with lessons learned
|
||||
|
||||
---
|
||||
|
||||
## Quarterly Maintenance Checklist
|
||||
|
||||
**Perform these checks quarterly:**
|
||||
|
||||
- [ ] Rotate Vault encryption key
|
||||
- [ ] Rotate database passwords
|
||||
- [ ] Review and update security policies
|
||||
- [ ] Conduct penetration testing
|
||||
- [ ] Review and optimize infrastructure costs
|
||||
- [ ] Update disaster recovery plan
|
||||
- [ ] Review team access and permissions
|
||||
- [ ] Conduct deployment drill with team
|
||||
- [ ] Review compliance requirements
|
||||
- [ ] Update technical documentation
|
||||
|
||||
---
|
||||
|
||||
## Emergency Contacts
|
||||
|
||||
**Fill this in and keep it secure:**
|
||||
|
||||
```
|
||||
Server Provider: _______________________
|
||||
Support Phone: _________________________
|
||||
Support Email: _________________________
|
||||
|
||||
Domain Registrar: ______________________
|
||||
Support Phone: _________________________
|
||||
Support Email: _________________________
|
||||
|
||||
SSL Provider: __________________________
|
||||
Support Phone: _________________________
|
||||
Support Email: _________________________
|
||||
|
||||
Database Backup Location: ______________
|
||||
Vault Key Location: ____________________
|
||||
SSH Key Location: ______________________
|
||||
|
||||
Team Lead: _____________________________
|
||||
On-Call Phone: _________________________
|
||||
|
||||
DevOps Lead: ___________________________
|
||||
On-Call Phone: _________________________
|
||||
|
||||
Security Contact: ______________________
|
||||
Emergency Phone: _______________________
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Sign-Off
|
||||
|
||||
**Deployment Details:**
|
||||
|
||||
```
|
||||
Date: _____________________
|
||||
Deployed By: ______________
|
||||
Version/Commit: ___________
|
||||
Environment: Production
|
||||
Deployment Method: [ ] Manual [ ] Script [ ] Ansible
|
||||
|
||||
Health Check Status: [ ] All Passing
|
||||
SSL Certificate: [ ] Valid
|
||||
Database Migrations: [ ] Applied
|
||||
Backups: [ ] Verified
|
||||
|
||||
Issues During Deployment:
|
||||
_____________________________________________
|
||||
_____________________________________________
|
||||
|
||||
Post-Deployment Notes:
|
||||
_____________________________________________
|
||||
_____________________________________________
|
||||
|
||||
Signed: ___________________ Date: __________
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Continuous Improvement
|
||||
|
||||
After each deployment, answer these questions:
|
||||
|
||||
1. **What went well?**
|
||||
- _______________________________________________
|
||||
- _______________________________________________
|
||||
|
||||
2. **What could be improved?**
|
||||
- _______________________________________________
|
||||
- _______________________________________________
|
||||
|
||||
3. **What was unexpected?**
|
||||
- _______________________________________________
|
||||
- _______________________________________________
|
||||
|
||||
4. **Action items for next deployment:**
|
||||
- _______________________________________________
|
||||
- _______________________________________________
|
||||
|
||||
5. **Documentation updates needed:**
|
||||
- _______________________________________________
|
||||
- _______________________________________________
|
||||
|
||||
---
|
||||
|
||||
**Remember**: This checklist should be updated after each deployment to reflect lessons learned and process improvements.
|
||||
@@ -1,96 +0,0 @@
|
||||
# Deployment System Restructuring Complete
|
||||
|
||||
## Summary
|
||||
|
||||
The deployment system has been successfully restructured from multiple scattered configurations into a modern, organized hybrid deployment system.
|
||||
|
||||
## What Was Done
|
||||
|
||||
### 1. Backup Creation
|
||||
Created `.deployment-backup/` directory containing all old deployment files:
|
||||
- `ansible/` - Multiple Ansible configurations (netcup-simple-deploy, nginx-cdn-germany, wireguard-server)
|
||||
- `x_ansible/` - Alternative Ansible setup
|
||||
- `ssl/` - SSL certificates for local development
|
||||
- `bin/` - Deployment utility scripts
|
||||
- `BACKUP_SUMMARY.md` - Detailed backup documentation
|
||||
|
||||
### 2. New Structure Creation
|
||||
Created modern `deployment/` directory with four main components:
|
||||
|
||||
**Infrastructure** (`deployment/infrastructure/`)
|
||||
- Ansible playbooks for server setup and management
|
||||
- Environment-specific inventories
|
||||
- Reusable roles for common tasks
|
||||
- Configuration management via group_vars
|
||||
|
||||
**Applications** (`deployment/applications/`)
|
||||
- Docker Compose configurations per environment
|
||||
- Production, staging, and development setups
|
||||
- Service orchestration and health monitoring
|
||||
- Environment-specific optimizations
|
||||
|
||||
**Scripts** (`deployment/scripts/`)
|
||||
- Automated deployment orchestration
|
||||
- Setup, rollback, and utility scripts
|
||||
- Health checking and monitoring tools
|
||||
- Integration with infrastructure and applications
|
||||
|
||||
**Configs** (`deployment/configs/`)
|
||||
- Configuration templates for all services
|
||||
- Nginx, PHP, MySQL, and SSL configurations
|
||||
- Environment-specific template variables
|
||||
- Monitoring and logging configurations
|
||||
|
||||
## Key Improvements
|
||||
|
||||
✅ **Separation of Concerns**: Clear distinction between infrastructure and application deployment
|
||||
✅ **Environment Management**: Dedicated configurations for production, staging, development
|
||||
✅ **Docker Integration**: Full containerization with Docker Compose
|
||||
✅ **Automation**: Streamlined deployment workflows
|
||||
✅ **Configuration Management**: Centralized template system
|
||||
✅ **Documentation**: Comprehensive README files for each component
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Infrastructure Setup** (`deployment/infrastructure/`)
|
||||
- Create Ansible inventories for environments
|
||||
- Develop server setup playbooks
|
||||
- Configure security and Docker roles
|
||||
|
||||
2. **Application Configuration** (`deployment/applications/`)
|
||||
- Create environment-specific Docker Compose files
|
||||
- Configure service networking and volumes
|
||||
- Set up health checks and monitoring
|
||||
|
||||
3. **Script Development** (`deployment/scripts/`)
|
||||
- Implement main deployment orchestration script
|
||||
- Create setup and rollback automation
|
||||
- Develop health monitoring tools
|
||||
|
||||
4. **Configuration Templates** (`deployment/configs/`)
|
||||
- Create Nginx configuration templates
|
||||
- Set up SSL certificate management
|
||||
- Configure environment file templates
|
||||
|
||||
## Migration Benefits
|
||||
|
||||
- **Maintainability**: Organized, documented structure
|
||||
- **Scalability**: Easy to add new environments or services
|
||||
- **Reliability**: Automated testing and rollback capabilities
|
||||
- **Security**: Modern security practices and SSL management
|
||||
- **Consistency**: Standardized deployment across environments
|
||||
|
||||
## Rollback Option
|
||||
|
||||
If needed, the old system can be quickly restored by moving files back from `.deployment-backup/` to their original locations. See `BACKUP_SUMMARY.md` for detailed instructions.
|
||||
|
||||
## Framework Integration
|
||||
|
||||
The new deployment system is specifically designed for the Custom PHP Framework with:
|
||||
- HTTPS-first configuration (framework requirement)
|
||||
- Docker-based architecture (current setup)
|
||||
- Production server targeting (94.16.110.151 with deploy user)
|
||||
- SSL certificate automation for framework's HTTPS requirement
|
||||
- Health check integration with framework's built-in endpoints
|
||||
|
||||
This modern deployment system provides a solid foundation for reliable, automated deployment of the Custom PHP Framework across all environments.
|
||||
@@ -1,568 +0,0 @@
|
||||
# Production Deployment Infrastructure - Summary
|
||||
|
||||
**Project**: Custom PHP Framework
|
||||
**Status**: ✅ Complete
|
||||
**Date**: January 2025
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Complete production deployment infrastructure has been implemented for the Custom PHP Framework, providing multiple deployment paths from quick manual setup to fully automated infrastructure as code.
|
||||
|
||||
---
|
||||
|
||||
## Completed Components
|
||||
|
||||
### 1. Health Check & Monitoring System ✅
|
||||
|
||||
**Location**: `src/Application/Health/`, `src/Application/Metrics/`
|
||||
|
||||
**Features**:
|
||||
- Multiple health check endpoints for different use cases
|
||||
- Automatic health check discovery via attributes
|
||||
- Prometheus-compatible metrics endpoint
|
||||
- Real-time performance monitoring
|
||||
- Health check categories (Database, Cache, Security, Infrastructure)
|
||||
|
||||
**Endpoints**:
|
||||
```
|
||||
GET /health/summary - Quick health overview
|
||||
GET /health/detailed - Comprehensive health report
|
||||
GET /health/checks - List all registered checks
|
||||
GET /health/category/{cat} - Category-specific checks
|
||||
GET /metrics - Prometheus metrics
|
||||
GET /metrics/json - JSON metrics
|
||||
```
|
||||
|
||||
**Health Checks Implemented**:
|
||||
- ✅ Database connectivity and performance
|
||||
- ✅ Cache system health (Redis/File)
|
||||
- ✅ Queue system monitoring
|
||||
- ✅ SSL certificate validity (30-day warning, 7-day critical)
|
||||
- ✅ Disk space monitoring
|
||||
- ✅ Memory usage monitoring
|
||||
- ✅ Vault availability
|
||||
|
||||
---
|
||||
|
||||
### 2. Production Logging Configuration ✅
|
||||
|
||||
**Location**: `src/Framework/Logging/ProductionLogConfig.php`
|
||||
|
||||
**Available Configurations**:
|
||||
|
||||
| Configuration | Use Case | Performance | Volume Reduction |
|
||||
|---------------|----------|-------------|------------------|
|
||||
| **production()** | Standard production | 10K+ logs/sec | Baseline |
|
||||
| **highPerformance()** | High traffic (>100 req/s) | 50K+ logs/sec | 80-90% |
|
||||
| **productionWithAggregation()** | Repetitive patterns | 20K+ logs/sec | 70-90% |
|
||||
| **debug()** | Temporary troubleshooting | 2-3ms latency | N/A (verbose) |
|
||||
| **staging()** | Pre-production testing | Standard | N/A |
|
||||
|
||||
**Features**:
|
||||
- Resilient logging with automatic fallback
|
||||
- Buffered writes for performance (100 entries, 5s flush)
|
||||
- 14-day rotating log files
|
||||
- Structured JSON logs with request/trace context
|
||||
- Intelligent sampling and aggregation
|
||||
- Integration with Prometheus metrics
|
||||
|
||||
**Documentation**: [production-logging.md](production-logging.md)
|
||||
|
||||
---
|
||||
|
||||
### 3. Deployment Documentation Suite ✅
|
||||
|
||||
Six comprehensive guides covering all deployment scenarios:
|
||||
|
||||
#### 3.1. Quick Start Guide
|
||||
**File**: [QUICKSTART.md](QUICKSTART.md)
|
||||
**Purpose**: Get to production in 30 minutes
|
||||
**Target**: First-time deployment, quick setup
|
||||
|
||||
**Contents**:
|
||||
- 10-step deployment process
|
||||
- Minimal configuration required
|
||||
- SSL certificate automation
|
||||
- Vault key generation
|
||||
- Database initialization
|
||||
- Health verification
|
||||
- Basic troubleshooting
|
||||
|
||||
#### 3.2. Deployment Checklist
|
||||
**File**: [DEPLOYMENT_CHECKLIST.md](DEPLOYMENT_CHECKLIST.md)
|
||||
**Purpose**: Ensure nothing is missed
|
||||
**Target**: Compliance verification, team coordination
|
||||
|
||||
**Contents**:
|
||||
- Pre-deployment checklist (Infrastructure, Security, Code)
|
||||
- Step-by-step deployment verification
|
||||
- Post-deployment security hardening
|
||||
- Maintenance schedules (weekly, monthly, quarterly)
|
||||
- Emergency contacts template
|
||||
- Deployment sign-off form
|
||||
- Continuous improvement framework
|
||||
|
||||
#### 3.3. Complete Deployment Workflow
|
||||
**File**: [DEPLOYMENT_WORKFLOW.md](DEPLOYMENT_WORKFLOW.md)
|
||||
**Purpose**: Detailed deployment lifecycle
|
||||
**Target**: Understanding complete process
|
||||
|
||||
**Contents**:
|
||||
- **Phase 1**: Initial Server Setup (one-time)
|
||||
- Server preparation
|
||||
- SSL certificate with Let's Encrypt
|
||||
- Vault key generation
|
||||
- Environment configuration
|
||||
- **Phase 2**: Initial Deployment
|
||||
- Docker container setup
|
||||
- Database migrations
|
||||
- Health check verification
|
||||
- Nginx reverse proxy
|
||||
- **Phase 3**: Ongoing Deployment
|
||||
- Automated deployment scripts
|
||||
- Zero-downtime deployment
|
||||
- Manual deployment steps
|
||||
- **Phase 4**: Monitoring Setup
|
||||
- Prometheus and Grafana
|
||||
- Alerting configuration
|
||||
|
||||
#### 3.4. Production Deployment Guide
|
||||
**File**: [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md)
|
||||
**Purpose**: Comprehensive infrastructure reference
|
||||
**Target**: Deep technical details
|
||||
|
||||
**Contents**:
|
||||
- Complete infrastructure setup
|
||||
- SSL/TLS configuration
|
||||
- Secrets management with Vault
|
||||
- Docker deployment
|
||||
- Database migration strategy
|
||||
- All monitoring endpoints documented
|
||||
- Logging configuration
|
||||
- Security best practices
|
||||
- Comprehensive troubleshooting
|
||||
- Rollback procedures
|
||||
- Maintenance tasks
|
||||
|
||||
#### 3.5. Production Logging Guide
|
||||
**File**: [production-logging.md](production-logging.md)
|
||||
**Purpose**: Logging configuration and optimization
|
||||
**Target**: Production logging setup
|
||||
|
||||
**Contents**:
|
||||
- All ProductionLogConfig options explained
|
||||
- Environment-based configuration
|
||||
- Log rotation and retention policies
|
||||
- Structured JSON format
|
||||
- Metrics integration
|
||||
- Performance tuning guidelines
|
||||
- Troubleshooting common issues
|
||||
- Best practices
|
||||
|
||||
#### 3.6. Ansible Deployment Guide
|
||||
**File**: [ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md)
|
||||
**Purpose**: Infrastructure as Code automation
|
||||
**Target**: Multi-server, enterprise deployments
|
||||
|
||||
**Contents**:
|
||||
- Complete Ansible project structure
|
||||
- Ansible roles (common, docker, ssl, application)
|
||||
- Playbooks (site.yml, deploy.yml, rollback.yml, provision.yml)
|
||||
- Ansible Vault for secrets
|
||||
- CI/CD integration (GitHub Actions)
|
||||
- Comparison: Script-Based vs Ansible
|
||||
- Hybrid approach recommendation
|
||||
|
||||
#### 3.7. Deployment README
|
||||
**File**: [README.md](README.md)
|
||||
**Purpose**: Navigation and quick reference
|
||||
**Target**: All deployment scenarios
|
||||
|
||||
**Contents**:
|
||||
- Document overview and navigation
|
||||
- Which guide for which scenario
|
||||
- Deployment methods comparison
|
||||
- Common tasks quick reference
|
||||
- Troubleshooting quick reference
|
||||
- Support resources
|
||||
|
||||
---
|
||||
|
||||
## Deployment Options
|
||||
|
||||
### Option 1: Quick Start (Recommended for First Deployment)
|
||||
**Time**: 30 minutes
|
||||
**Best For**: Single server, getting started
|
||||
**Guide**: [QUICKSTART.md](QUICKSTART.md)
|
||||
|
||||
**Process**:
|
||||
1. Server setup (10 min)
|
||||
2. SSL certificate (5 min)
|
||||
3. Clone application (2 min)
|
||||
4. Generate secrets (3 min)
|
||||
5. Create environment file (5 min)
|
||||
6. Build and start containers (3 min)
|
||||
7. Initialize database (2 min)
|
||||
|
||||
### Option 2: Script-Based Deployment
|
||||
**Time**: 2 hours initial, 10 minutes ongoing
|
||||
**Best For**: Single server, repeatable deployments
|
||||
**Guide**: [DEPLOYMENT_WORKFLOW.md](DEPLOYMENT_WORKFLOW.md)
|
||||
|
||||
**Features**:
|
||||
- Automated deployment scripts
|
||||
- Zero-downtime blue-green deployment
|
||||
- Rollback support
|
||||
- Health check integration
|
||||
|
||||
**Scripts**:
|
||||
- `scripts/deployment/deploy-production.sh` - Standard deployment
|
||||
- `scripts/deployment/blue-green-deploy.sh` - Zero-downtime deployment
|
||||
- `scripts/deployment/blue-green-rollback.sh` - Safe rollback
|
||||
|
||||
### Option 3: Ansible Automation
|
||||
**Time**: 4 hours initial, 5 minutes ongoing
|
||||
**Best For**: Multiple servers, enterprise deployments
|
||||
**Guide**: [ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md)
|
||||
|
||||
**Features**:
|
||||
- Infrastructure as Code
|
||||
- Multi-server orchestration
|
||||
- Idempotent operations
|
||||
- Automated rollback
|
||||
- CI/CD integration
|
||||
|
||||
**Roles**:
|
||||
- **common**: System packages, firewall, directories
|
||||
- **docker**: Docker installation and configuration
|
||||
- **ssl**: Certificate management with auto-renewal
|
||||
- **application**: Git, composer, migrations, health checks
|
||||
|
||||
---
|
||||
|
||||
## Infrastructure Components
|
||||
|
||||
### SSL/TLS Management
|
||||
- ✅ Let's Encrypt integration
|
||||
- ✅ Automatic certificate renewal
|
||||
- ✅ 30-day expiration warning
|
||||
- ✅ 7-day critical alert
|
||||
- ✅ Health check integration
|
||||
|
||||
### Secrets Management
|
||||
- ✅ Vault encryption key generation
|
||||
- ✅ Encrypted secrets storage
|
||||
- ✅ Environment-based configuration
|
||||
- ✅ Key rotation procedures
|
||||
|
||||
### Docker Infrastructure
|
||||
- ✅ Production-ready docker-compose configuration
|
||||
- ✅ Container health checks
|
||||
- ✅ Resource limits and constraints
|
||||
- ✅ Logging configuration
|
||||
- ✅ Network isolation
|
||||
|
||||
### Database Management
|
||||
- ✅ Migration system with safe rollback architecture
|
||||
- ✅ Forward-only migrations by default
|
||||
- ✅ Optional SafelyReversible interface
|
||||
- ✅ Fix-forward strategy for unsafe changes
|
||||
- ✅ Automated migration execution
|
||||
|
||||
### Reverse Proxy
|
||||
- ✅ Nginx configuration
|
||||
- ✅ SSL/TLS termination
|
||||
- ✅ Proxy headers
|
||||
- ✅ Health check routing
|
||||
- ✅ Static asset serving
|
||||
|
||||
---
|
||||
|
||||
## Security Features
|
||||
|
||||
### Web Application Firewall (WAF)
|
||||
- ✅ SQL injection detection
|
||||
- ✅ XSS protection
|
||||
- ✅ Path traversal prevention
|
||||
- ✅ Command injection detection
|
||||
- ✅ Rate limiting
|
||||
- ✅ Suspicious user agent blocking
|
||||
|
||||
### Security Headers
|
||||
- ✅ X-Frame-Options: SAMEORIGIN
|
||||
- ✅ X-Content-Type-Options: nosniff
|
||||
- ✅ X-XSS-Protection: 1; mode=block
|
||||
- ✅ Strict-Transport-Security (HSTS)
|
||||
- ✅ Content-Security-Policy (CSP)
|
||||
- ✅ Referrer-Policy
|
||||
- ✅ Permissions-Policy
|
||||
|
||||
### Authentication & Authorization
|
||||
- ✅ IP-based authentication for admin routes
|
||||
- ✅ Session-based authentication
|
||||
- ✅ Token-based authentication
|
||||
- ✅ CSRF protection
|
||||
- ✅ Rate limiting
|
||||
|
||||
### Hardening
|
||||
- ✅ UFW firewall configuration
|
||||
- ✅ SSH key-only authentication
|
||||
- ✅ Fail2Ban integration
|
||||
- ✅ Regular security updates
|
||||
- ✅ OWASP security event logging
|
||||
|
||||
---
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
### Health Checks
|
||||
- ✅ Multiple endpoints for different use cases
|
||||
- ✅ Category-based filtering
|
||||
- ✅ Automatic service discovery
|
||||
- ✅ Response time tracking
|
||||
- ✅ Detailed error reporting
|
||||
|
||||
### Metrics
|
||||
- ✅ Prometheus-compatible metrics
|
||||
- ✅ Health check metrics
|
||||
- ✅ Performance metrics
|
||||
- ✅ Resource utilization metrics
|
||||
- ✅ Custom business metrics
|
||||
|
||||
### Logging
|
||||
- ✅ Structured JSON logs
|
||||
- ✅ Request ID tracing
|
||||
- ✅ Distributed tracing support
|
||||
- ✅ Performance metrics
|
||||
- ✅ Error aggregation
|
||||
|
||||
### Alerting
|
||||
- ✅ Prometheus alert rules
|
||||
- ✅ Health check failure alerts
|
||||
- ✅ Disk space alerts
|
||||
- ✅ SSL expiration alerts
|
||||
- ✅ Custom alert rules
|
||||
|
||||
---
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
### Health Check Performance
|
||||
- **Response Time**: <100ms for summary endpoint
|
||||
- **Detailed Check**: <500ms with all checks
|
||||
- **Throughput**: 1000+ requests/second
|
||||
- **Timeout Protection**: Configurable per-check timeouts
|
||||
|
||||
### Logging Performance
|
||||
- **Standard Production**: 10,000+ logs/second
|
||||
- **High Performance**: 50,000+ logs/second (with sampling)
|
||||
- **Write Latency**: <1ms (buffered)
|
||||
- **Disk I/O**: Minimized via buffering and rotation
|
||||
|
||||
### Deployment Performance
|
||||
- **Manual Deployment**: ~15 minutes
|
||||
- **Automated Deployment**: ~5-10 minutes
|
||||
- **Zero-Downtime Deployment**: ~10-15 minutes
|
||||
- **Rollback**: ~5 minutes
|
||||
|
||||
---
|
||||
|
||||
## Testing & Validation
|
||||
|
||||
### Pre-Deployment Testing
|
||||
- ✅ Unit tests passing
|
||||
- ✅ Integration tests passing
|
||||
- ✅ Migration tests
|
||||
- ✅ Health check tests
|
||||
- ✅ Security tests
|
||||
|
||||
### Deployment Verification
|
||||
- ✅ Container health checks
|
||||
- ✅ Application health endpoints
|
||||
- ✅ SSL certificate validation
|
||||
- ✅ Database migration verification
|
||||
- ✅ Performance baseline
|
||||
|
||||
### Post-Deployment Monitoring
|
||||
- ✅ Health check monitoring
|
||||
- ✅ Metrics collection
|
||||
- ✅ Log aggregation
|
||||
- ✅ Alert verification
|
||||
- ✅ User acceptance testing
|
||||
|
||||
---
|
||||
|
||||
## Maintenance Procedures
|
||||
|
||||
### Weekly Maintenance
|
||||
- Review application logs
|
||||
- Check disk space (<80%)
|
||||
- Verify health check status
|
||||
- Verify backups
|
||||
- Check SSL certificate (>30 days)
|
||||
- Review security logs
|
||||
|
||||
### Monthly Maintenance
|
||||
- Apply system security updates
|
||||
- Update dependencies
|
||||
- Rotate secrets if required
|
||||
- Review and archive logs
|
||||
- Security audit
|
||||
- Database optimization
|
||||
|
||||
### Quarterly Maintenance
|
||||
- Rotate Vault encryption key
|
||||
- Rotate database passwords
|
||||
- Penetration testing
|
||||
- Infrastructure cost review
|
||||
- Disaster recovery drill
|
||||
- Team training
|
||||
|
||||
---
|
||||
|
||||
## Rollback & Disaster Recovery
|
||||
|
||||
### Rollback Procedures
|
||||
- ✅ Blue-green deployment rollback
|
||||
- ✅ Database migration rollback (safe migrations)
|
||||
- ✅ Fix-forward strategy (unsafe migrations)
|
||||
- ✅ Container version rollback
|
||||
- ✅ Configuration rollback
|
||||
|
||||
### Disaster Recovery
|
||||
- ✅ Automated database backups (daily)
|
||||
- ✅ Vault backup procedures
|
||||
- ✅ Configuration backups
|
||||
- ✅ Off-site backup storage
|
||||
- ✅ Recovery testing procedures
|
||||
|
||||
---
|
||||
|
||||
## Documentation Highlights
|
||||
|
||||
### Comprehensive Coverage
|
||||
- 6 deployment guides totaling 140+ pages
|
||||
- Step-by-step instructions for all scenarios
|
||||
- Troubleshooting guides for common issues
|
||||
- Best practices and recommendations
|
||||
- Security considerations
|
||||
- Performance tuning guidelines
|
||||
|
||||
### Accessibility
|
||||
- Quick start for fast deployment (30 min)
|
||||
- Detailed guides for deep understanding
|
||||
- Printable checklists for verification
|
||||
- Navigation guide for finding information
|
||||
- Cross-references between documents
|
||||
|
||||
### Maintainability
|
||||
- Continuous improvement framework
|
||||
- Post-deployment feedback template
|
||||
- Lessons learned documentation
|
||||
- Version history tracking
|
||||
- Regular update procedures
|
||||
|
||||
---
|
||||
|
||||
## Team Readiness
|
||||
|
||||
### Documentation
|
||||
- ✅ Complete deployment documentation
|
||||
- ✅ Troubleshooting guides
|
||||
- ✅ Runbooks for common operations
|
||||
- ✅ Emergency procedures
|
||||
- ✅ Contact information templates
|
||||
|
||||
### Training Materials
|
||||
- ✅ Quick start guide for new team members
|
||||
- ✅ Detailed workflow documentation
|
||||
- ✅ Video walkthrough opportunities
|
||||
- ✅ FAQ sections
|
||||
- ✅ Best practices documentation
|
||||
|
||||
### Support
|
||||
- ✅ Internal documentation references
|
||||
- ✅ External resource links
|
||||
- ✅ Community support channels
|
||||
- ✅ Escalation procedures
|
||||
- ✅ On-call rotation guidelines
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Recommended Actions
|
||||
|
||||
1. **First Deployment**: Follow [QUICKSTART.md](QUICKSTART.md)
|
||||
2. **Team Review**: Distribute [DEPLOYMENT_README.md](README.md) to team
|
||||
3. **Production Deploy**: Schedule deployment using deployment checklist
|
||||
4. **Monitoring Setup**: Configure Prometheus/Grafana (Phase 4 in workflow)
|
||||
5. **Security Hardening**: Complete post-deployment security checklist
|
||||
6. **Team Training**: Conduct deployment drill with team
|
||||
7. **Documentation Review**: Schedule quarterly documentation updates
|
||||
|
||||
### Future Enhancements
|
||||
|
||||
**Potential additions** (not required for production):
|
||||
- Kubernetes deployment option (for larger scale)
|
||||
- Multi-region deployment strategies
|
||||
- Advanced monitoring dashboards
|
||||
- Automated security scanning integration
|
||||
- Performance testing automation
|
||||
- Chaos engineering practices
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### Deployment Success
|
||||
- ✅ All health checks passing
|
||||
- ✅ SSL certificate valid
|
||||
- ✅ Zero errors in logs
|
||||
- ✅ Metrics collecting correctly
|
||||
- ✅ Backups running successfully
|
||||
|
||||
### Operational Success
|
||||
- ⏱️ Deployment time: <30 minutes (target)
|
||||
- 🎯 Uptime: 99.9% (target)
|
||||
- ⚡ Response time: <200ms (target)
|
||||
- 🔒 Security: Zero critical vulnerabilities
|
||||
- 📊 Monitoring: 100% coverage
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Custom PHP Framework now has **production-ready deployment infrastructure** with:
|
||||
|
||||
✅ **Multiple deployment paths** (Quick, Script-Based, Ansible)
|
||||
✅ **Comprehensive monitoring** (Health checks, Metrics, Logging)
|
||||
✅ **Security hardening** (WAF, SSL, Vault, Headers)
|
||||
✅ **Zero-downtime deployments** (Blue-green strategy)
|
||||
✅ **Safe rollback procedures** (Migration architecture)
|
||||
✅ **Complete documentation** (6 comprehensive guides)
|
||||
✅ **Team readiness** (Checklists, runbooks, procedures)
|
||||
|
||||
**The infrastructure is ready for production deployment.**
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Need | Document | Time |
|
||||
|------|----------|------|
|
||||
| Deploy now | [QUICKSTART.md](QUICKSTART.md) | 30 min |
|
||||
| Understand process | [DEPLOYMENT_WORKFLOW.md](DEPLOYMENT_WORKFLOW.md) | 2 hours |
|
||||
| Deep technical details | [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md) | Reference |
|
||||
| Logging setup | [production-logging.md](production-logging.md) | 30 min |
|
||||
| Automation | [ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md) | 4 hours |
|
||||
| Verification | [DEPLOYMENT_CHECKLIST.md](DEPLOYMENT_CHECKLIST.md) | Ongoing |
|
||||
| Navigation | [README.md](README.md) | Reference |
|
||||
|
||||
---
|
||||
|
||||
**For questions or support, see [README.md](README.md) → Support and Resources**
|
||||
|
||||
**Ready to deploy? → [QUICKSTART.md](QUICKSTART.md)**
|
||||
@@ -1,720 +0,0 @@
|
||||
# Concrete Deployment Workflow
|
||||
|
||||
Schritt-für-Schritt Anleitung für das Production Deployment mit und ohne Ansible.
|
||||
|
||||
## Deployment-Optionen
|
||||
|
||||
Das Framework bietet **zwei Deployment-Strategien**:
|
||||
|
||||
1. **Manual/Script-Based** (einfach, für Single-Server)
|
||||
2. **Ansible-Based** (automatisiert, für Multi-Server)
|
||||
|
||||
Beide Strategien nutzen Docker Compose als Container-Orchestrierung.
|
||||
|
||||
---
|
||||
|
||||
## Option 1: Manual/Script-Based Deployment (Empfohlen für Start)
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- Server mit Ubuntu 22.04 LTS
|
||||
- SSH-Zugriff mit sudo-Rechten
|
||||
- Domain mit DNS konfiguriert
|
||||
- Git Repository Access
|
||||
|
||||
### Phase 1: Initiales Server Setup (Einmalig)
|
||||
|
||||
#### 1.1 Server vorbereiten
|
||||
|
||||
```bash
|
||||
# SSH-Verbindung zum Server
|
||||
ssh user@your-server.com
|
||||
|
||||
# System aktualisieren
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# Docker installieren
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
sudo sh get-docker.sh
|
||||
sudo usermod -aG docker $USER
|
||||
|
||||
# Docker Compose installieren
|
||||
sudo apt install -y docker-compose-plugin
|
||||
|
||||
# Neuanmeldung für Docker-Gruppe
|
||||
exit
|
||||
ssh user@your-server.com
|
||||
|
||||
# Verify
|
||||
docker --version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
#### 1.2 Projektverzeichnisse erstellen
|
||||
|
||||
```bash
|
||||
# Verzeichnisstruktur anlegen
|
||||
sudo mkdir -p /var/www/app
|
||||
sudo mkdir -p /var/log/app
|
||||
sudo mkdir -p /opt/vault
|
||||
sudo mkdir -p /etc/ssl/app
|
||||
sudo mkdir -p /backups/database
|
||||
sudo mkdir -p /backups/volumes
|
||||
|
||||
# Berechtigungen setzen
|
||||
sudo chown -R $USER:$USER /var/www/app
|
||||
sudo chown -R www-data:www-data /var/log/app
|
||||
sudo chown -R www-data:www-data /opt/vault
|
||||
sudo chmod 755 /var/www/app
|
||||
sudo chmod 755 /var/log/app
|
||||
sudo chmod 700 /opt/vault
|
||||
```
|
||||
|
||||
#### 1.3 Repository klonen
|
||||
|
||||
```bash
|
||||
cd /var/www
|
||||
git clone git@github.com:yourusername/app.git
|
||||
cd app
|
||||
|
||||
# Production branch
|
||||
git checkout production
|
||||
|
||||
# Scripts ausführbar machen
|
||||
chmod +x scripts/deployment/*.sh
|
||||
```
|
||||
|
||||
#### 1.4 SSL-Zertifikat einrichten
|
||||
|
||||
```bash
|
||||
# Nginx für Certbot installieren
|
||||
sudo apt install -y nginx certbot python3-certbot-nginx
|
||||
|
||||
# Temporäre Nginx-Config für Certbot
|
||||
sudo tee /etc/nginx/sites-available/temp-certbot > /dev/null <<'EOF'
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com www.yourdomain.com;
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
sudo ln -s /etc/nginx/sites-available/temp-certbot /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
|
||||
# Zertifikat holen
|
||||
sudo certbot certonly --webroot \
|
||||
-w /var/www/certbot \
|
||||
-d yourdomain.com \
|
||||
-d www.yourdomain.com \
|
||||
--email your-email@example.com \
|
||||
--agree-tos \
|
||||
--no-eff-email
|
||||
|
||||
# Zertifikate für Container verfügbar machen
|
||||
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem /etc/ssl/app/cert.pem
|
||||
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem /etc/ssl/app/key.pem
|
||||
sudo chmod 644 /etc/ssl/app/cert.pem
|
||||
sudo chmod 600 /etc/ssl/app/key.pem
|
||||
|
||||
# Auto-Renewal einrichten
|
||||
echo "0 3 * * * root certbot renew --quiet && cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem /etc/ssl/app/cert.pem && cp /etc/letsencrypt/live/yourdomain.com/privkey.pem /etc/ssl/app/key.pem && docker compose -f /var/www/app/docker-compose.production.yml restart nginx" | sudo tee -a /etc/crontab
|
||||
```
|
||||
|
||||
#### 1.5 Vault Encryption Key generieren
|
||||
|
||||
```bash
|
||||
cd /var/www/app
|
||||
|
||||
# Key generieren
|
||||
php scripts/deployment/generate-vault-key.php
|
||||
|
||||
# Output kopieren (sicher speichern!):
|
||||
# VAULT_ENCRYPTION_KEY=base64encodedkey...
|
||||
|
||||
# In 1Password, Bitwarden, oder AWS Secrets Manager speichern
|
||||
```
|
||||
|
||||
#### 1.6 Environment File erstellen
|
||||
|
||||
```bash
|
||||
cd /var/www/app
|
||||
|
||||
# Template kopieren
|
||||
cp .env.example .env.production
|
||||
|
||||
# Mit echten Production-Werten füllen
|
||||
nano .env.production
|
||||
```
|
||||
|
||||
**Minimal erforderliche Werte**:
|
||||
```env
|
||||
# Application
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_URL=https://yourdomain.com
|
||||
|
||||
# Database
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=db
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=app_production
|
||||
DB_USERNAME=app_user
|
||||
DB_PASSWORD=<strong-database-password>
|
||||
|
||||
# Cache & Queue
|
||||
CACHE_DRIVER=redis
|
||||
QUEUE_DRIVER=redis
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=<strong-redis-password>
|
||||
|
||||
# Vault
|
||||
VAULT_ENCRYPTION_KEY=<from-generate-vault-key>
|
||||
|
||||
# Admin Access
|
||||
ADMIN_ALLOWED_IPS=your.ip.address.here
|
||||
|
||||
# Logging
|
||||
LOG_PATH=/var/log/app
|
||||
LOG_LEVEL=info
|
||||
```
|
||||
|
||||
#### 1.7 Secrets in Vault speichern
|
||||
|
||||
```bash
|
||||
# Secrets-Setup Script ausführen
|
||||
php scripts/deployment/setup-production-secrets.php
|
||||
|
||||
# Manuelle Secrets hinzufügen
|
||||
docker compose -f docker-compose.production.yml run --rm php php -r "
|
||||
require 'vendor/autoload.php';
|
||||
\$vault = new App\Framework\Vault\EncryptedVault(
|
||||
\$_ENV['VAULT_ENCRYPTION_KEY'],
|
||||
'/opt/vault/production.vault'
|
||||
);
|
||||
|
||||
// API Keys
|
||||
\$vault->set(
|
||||
App\Framework\Vault\SecretKey::from('stripe_secret_key'),
|
||||
App\Framework\Vault\SecretValue::from('sk_live_...')
|
||||
);
|
||||
|
||||
// Mail Password
|
||||
\$vault->set(
|
||||
App\Framework\Vault\SecretKey::from('mail_password'),
|
||||
App\Framework\Vault\SecretValue::from('your-mail-password')
|
||||
);
|
||||
|
||||
echo 'Secrets stored successfully\n';
|
||||
"
|
||||
```
|
||||
|
||||
### Phase 2: Initiales Deployment
|
||||
|
||||
#### 2.1 Dependencies installieren
|
||||
|
||||
```bash
|
||||
cd /var/www/app
|
||||
|
||||
# Composer Dependencies
|
||||
docker compose -f docker-compose.production.yml run --rm php composer install --no-dev --optimize-autoloader
|
||||
|
||||
# NPM Dependencies und Build
|
||||
docker compose -f docker-compose.production.yml run --rm nodejs npm ci
|
||||
docker compose -f docker-compose.production.yml run --rm nodejs npm run build
|
||||
```
|
||||
|
||||
#### 2.2 Container starten
|
||||
|
||||
```bash
|
||||
# Docker Images bauen
|
||||
docker compose -f docker-compose.production.yml build
|
||||
|
||||
# Container starten
|
||||
docker compose -f docker-compose.production.yml up -d
|
||||
|
||||
# Logs verfolgen
|
||||
docker compose -f docker-compose.production.yml logs -f
|
||||
```
|
||||
|
||||
#### 2.3 Datenbank initialisieren
|
||||
|
||||
```bash
|
||||
# Warten bis MySQL ready ist
|
||||
sleep 30
|
||||
|
||||
# Migrations ausführen
|
||||
docker compose -f docker-compose.production.yml exec php php console.php db:migrate
|
||||
|
||||
# Verify
|
||||
docker compose -f docker-compose.production.yml exec php php console.php db:status
|
||||
```
|
||||
|
||||
#### 2.4 Health Checks verifizieren
|
||||
|
||||
```bash
|
||||
# Health Check (sollte 200 zurückgeben)
|
||||
curl -f http://localhost/health || echo "Health check failed"
|
||||
|
||||
# Detailed Health Report
|
||||
curl -s http://localhost/health/detailed | jq
|
||||
|
||||
# Alle Checks sollten "healthy" sein
|
||||
curl -s http://localhost/health/summary | jq '.summary'
|
||||
```
|
||||
|
||||
#### 2.5 Nginx Reverse Proxy konfigurieren
|
||||
|
||||
```bash
|
||||
# System Nginx als Reverse Proxy
|
||||
sudo tee /etc/nginx/sites-available/app > /dev/null <<'EOF'
|
||||
upstream app_backend {
|
||||
server localhost:8080;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com www.yourdomain.com;
|
||||
|
||||
# Redirect HTTP to HTTPS
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name yourdomain.com www.yourdomain.com;
|
||||
|
||||
ssl_certificate /etc/ssl/app/cert.pem;
|
||||
ssl_certificate_key /etc/ssl/app/key.pem;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
# Security Headers
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# Proxy to Docker container
|
||||
location / {
|
||||
proxy_pass http://app_backend;
|
||||
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;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Increase timeouts for long-running requests
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Enable site
|
||||
sudo ln -sf /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
sudo rm -f /etc/nginx/sites-enabled/temp-certbot
|
||||
|
||||
# Test config
|
||||
sudo nginx -t
|
||||
|
||||
# Reload
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
#### 2.6 Finaler Test
|
||||
|
||||
```bash
|
||||
# HTTPS Health Check
|
||||
curl -f https://yourdomain.com/health || echo "HTTPS health check failed"
|
||||
|
||||
# SSL Test
|
||||
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com < /dev/null
|
||||
|
||||
# Metrics
|
||||
curl https://yourdomain.com/metrics | head -20
|
||||
|
||||
# Homepage
|
||||
curl -I https://yourdomain.com
|
||||
```
|
||||
|
||||
### Phase 3: Laufendes Deployment (Updates)
|
||||
|
||||
#### 3.1 Automatisches Deployment Script nutzen
|
||||
|
||||
```bash
|
||||
cd /var/www/app
|
||||
|
||||
# Standard Deployment
|
||||
./scripts/deployment/deploy-production.sh
|
||||
|
||||
# Mit spezifischem Branch
|
||||
./scripts/deployment/deploy-production.sh --branch production-v2.1.0
|
||||
|
||||
# Dry-Run (keine Änderungen)
|
||||
./scripts/deployment/deploy-production.sh --dry-run
|
||||
```
|
||||
|
||||
Das Script führt automatisch aus:
|
||||
1. ✅ Pre-deployment Checks
|
||||
2. ✅ Backup Erstellung
|
||||
3. ✅ Git Pull
|
||||
4. ✅ Composer/NPM Install
|
||||
5. ✅ Docker Image Build
|
||||
6. ✅ Database Migrations
|
||||
7. ✅ Container Restart
|
||||
8. ✅ Health Checks
|
||||
9. ✅ Smoke Tests
|
||||
|
||||
#### 3.2 Zero-Downtime Deployment (Blue-Green)
|
||||
|
||||
```bash
|
||||
# Blue-Green Deployment für Zero-Downtime
|
||||
./scripts/deployment/blue-green-deploy.sh
|
||||
|
||||
# Bei Problemen: Rollback
|
||||
./scripts/deployment/blue-green-rollback.sh
|
||||
```
|
||||
|
||||
#### 3.3 Manuelles Deployment (wenn Scripts nicht verfügbar)
|
||||
|
||||
```bash
|
||||
cd /var/www/app
|
||||
|
||||
# 1. Pre-Deployment Backup
|
||||
docker compose -f docker-compose.production.yml exec db \
|
||||
mysqldump -u app_user -p<password> app_production \
|
||||
> /backups/database/backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
|
||||
# 2. Git Pull
|
||||
git fetch origin production
|
||||
git checkout production
|
||||
git pull origin production
|
||||
|
||||
# 3. Dependencies aktualisieren
|
||||
docker compose -f docker-compose.production.yml run --rm php \
|
||||
composer install --no-dev --optimize-autoloader
|
||||
|
||||
# 4. Frontend Build (falls geändert)
|
||||
docker compose -f docker-compose.production.yml run --rm nodejs npm ci
|
||||
docker compose -f docker-compose.production.yml run --rm nodejs npm run build
|
||||
|
||||
# 5. Images neu bauen
|
||||
docker compose -f docker-compose.production.yml build
|
||||
|
||||
# 6. Migrations ausführen
|
||||
docker compose -f docker-compose.production.yml exec php php console.php db:migrate
|
||||
|
||||
# 7. Container neu starten
|
||||
docker compose -f docker-compose.production.yml up -d --no-deps --build php nginx
|
||||
|
||||
# 8. Health Check
|
||||
curl -f https://yourdomain.com/health/summary
|
||||
|
||||
# 9. Logs prüfen
|
||||
docker compose -f docker-compose.production.yml logs -f --tail=100 php
|
||||
```
|
||||
|
||||
### Phase 4: Monitoring Setup
|
||||
|
||||
#### 4.1 Prometheus (Optional)
|
||||
|
||||
```yaml
|
||||
# docker-compose.monitoring.yml erstellen
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus-data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
restart: unless-stopped
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=<strong-password>
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
prometheus-data:
|
||||
grafana-data:
|
||||
```
|
||||
|
||||
```yaml
|
||||
# prometheus.yml
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'app'
|
||||
static_configs:
|
||||
- targets: ['app-nginx:80']
|
||||
metrics_path: '/metrics'
|
||||
```
|
||||
|
||||
```bash
|
||||
# Monitoring starten
|
||||
docker compose -f docker-compose.monitoring.yml up -d
|
||||
|
||||
# Grafana öffnen: http://your-server:3000
|
||||
# Login: admin / <strong-password>
|
||||
# Dashboard importieren: docs/deployment/grafana-dashboard.json
|
||||
```
|
||||
|
||||
#### 4.2 Alerting (Optional)
|
||||
|
||||
```bash
|
||||
# Simple Alert Script für kritische Health Checks
|
||||
tee /opt/health-check-alert.sh > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
HEALTH=$(curl -s http://localhost/health/summary | jq -r '.overall_healthy')
|
||||
|
||||
if [ "$HEALTH" != "true" ]; then
|
||||
# Alert senden (Email, Slack, PagerDuty, etc.)
|
||||
curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"text":"🚨 Production Health Check FAILED!"}'
|
||||
fi
|
||||
EOF
|
||||
|
||||
chmod +x /opt/health-check-alert.sh
|
||||
|
||||
# Crontab: Jede 5 Minuten prüfen
|
||||
echo "*/5 * * * * /opt/health-check-alert.sh" | crontab -
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Option 2: Ansible-Based Deployment (Multi-Server)
|
||||
|
||||
### Wann Ansible verwenden?
|
||||
|
||||
✅ **Verwende Ansible wenn**:
|
||||
- Mehrere Production Server (Load Balancing)
|
||||
- Staging + Production Environments
|
||||
- Infrastructure as Code gewünscht
|
||||
- Wiederholbare, idempotente Deployments
|
||||
- Team-basierte Deployments
|
||||
|
||||
❌ **Ansible NICHT notwendig wenn**:
|
||||
- Einzelner Production Server
|
||||
- Einfache Infrastruktur
|
||||
- Kleine Team-Größe
|
||||
- Docker Compose Scripts ausreichend
|
||||
|
||||
### Ansible Setup
|
||||
|
||||
Siehe separate Dokumentation: [ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md)
|
||||
|
||||
**Kurzübersicht**:
|
||||
```bash
|
||||
# Ansible installieren
|
||||
pip install ansible
|
||||
|
||||
# Playbooks ausführen
|
||||
cd ansible
|
||||
ansible-playbook -i inventory/production site.yml
|
||||
|
||||
# Spezifische Playbooks
|
||||
ansible-playbook -i inventory/production playbooks/deploy.yml
|
||||
ansible-playbook -i inventory/production playbooks/rollback.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment-Checkliste
|
||||
|
||||
### Pre-Deployment
|
||||
|
||||
- [ ] Server vorbereitet und zugänglich
|
||||
- [ ] Domain DNS konfiguriert
|
||||
- [ ] SSL-Zertifikat vorhanden
|
||||
- [ ] Vault Encryption Key generiert und sicher gespeichert
|
||||
- [ ] Environment File `.env.production` erstellt
|
||||
- [ ] Secrets in Vault gespeichert
|
||||
- [ ] Docker und Docker Compose installiert
|
||||
- [ ] Nginx Reverse Proxy konfiguriert
|
||||
|
||||
### Initial Deployment
|
||||
|
||||
- [ ] Repository geklont
|
||||
- [ ] Dependencies installiert
|
||||
- [ ] Docker Images gebaut
|
||||
- [ ] Container gestartet
|
||||
- [ ] Datenbank migriert
|
||||
- [ ] Health Checks grün
|
||||
- [ ] HTTPS funktioniert
|
||||
- [ ] Monitoring konfiguriert (optional)
|
||||
|
||||
### Laufendes Deployment
|
||||
|
||||
- [ ] Backup erstellt
|
||||
- [ ] Git Pull erfolgreich
|
||||
- [ ] Dependencies aktualisiert
|
||||
- [ ] Frontend gebaut (falls nötig)
|
||||
- [ ] Images neu gebaut
|
||||
- [ ] Migrations ausgeführt
|
||||
- [ ] Container neu gestartet
|
||||
- [ ] Health Checks grün
|
||||
- [ ] Smoke Tests erfolgreich
|
||||
- [ ] Logs geprüft
|
||||
|
||||
### Post-Deployment
|
||||
|
||||
- [ ] Application erreichbar
|
||||
- [ ] Alle Features funktional
|
||||
- [ ] Performance akzeptabel
|
||||
- [ ] Monitoring aktiv
|
||||
- [ ] Logs rotieren
|
||||
- [ ] Backups funktionieren
|
||||
- [ ] Rollback-Plan getestet
|
||||
|
||||
---
|
||||
|
||||
## Rollback-Prozedur
|
||||
|
||||
### Quick Rollback
|
||||
|
||||
```bash
|
||||
cd /var/www/app
|
||||
|
||||
# 1. Zu vorherigem Commit
|
||||
git log --oneline -10 # Vorherigen Commit finden
|
||||
git checkout <previous-commit>
|
||||
|
||||
# 2. Dependencies (falls nötig)
|
||||
docker compose -f docker-compose.production.yml run --rm php \
|
||||
composer install --no-dev --optimize-autoloader
|
||||
|
||||
# 3. Migrations rückgängig
|
||||
docker compose -f docker-compose.production.yml exec php \
|
||||
php console.php db:rollback 3
|
||||
|
||||
# 4. Container neu starten
|
||||
docker compose -f docker-compose.production.yml up -d --build
|
||||
|
||||
# 5. Health Check
|
||||
curl -f https://yourdomain.com/health/summary
|
||||
```
|
||||
|
||||
### Database Rollback
|
||||
|
||||
```bash
|
||||
# Datenbank aus Backup wiederherstellen
|
||||
docker compose -f docker-compose.production.yml exec -T db \
|
||||
mysql -u app_user -p<password> app_production \
|
||||
< /backups/database/backup_20250115_120000.sql
|
||||
|
||||
# Verify
|
||||
docker compose -f docker-compose.production.yml exec php \
|
||||
php console.php db:status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Deployment
|
||||
|
||||
### Container starten nicht
|
||||
|
||||
```bash
|
||||
# Logs prüfen
|
||||
docker compose -f docker-compose.production.yml logs
|
||||
|
||||
# Port-Konflikte prüfen
|
||||
sudo netstat -tulpn | grep -E ':(80|443|3306|6379)'
|
||||
|
||||
# Container Status
|
||||
docker compose -f docker-compose.production.yml ps
|
||||
|
||||
# Neustart
|
||||
docker compose -f docker-compose.production.yml down
|
||||
docker compose -f docker-compose.production.yml up -d
|
||||
```
|
||||
|
||||
### Health Checks schlagen fehl
|
||||
|
||||
```bash
|
||||
# Detailed Health Report
|
||||
curl http://localhost/health/detailed | jq
|
||||
|
||||
# Spezifische Checks
|
||||
curl http://localhost/health/category/database | jq
|
||||
curl http://localhost/health/category/security | jq
|
||||
|
||||
# Container-Logs
|
||||
docker compose -f docker-compose.production.yml logs php
|
||||
docker compose -f docker-compose.production.yml logs nginx
|
||||
```
|
||||
|
||||
### Migrations schlagen fehl
|
||||
|
||||
```bash
|
||||
# Migration Status
|
||||
docker compose -f docker-compose.production.yml exec php \
|
||||
php console.php db:status
|
||||
|
||||
# Migrations rollback
|
||||
docker compose -f docker-compose.production.yml exec php \
|
||||
php console.php db:rollback 1
|
||||
|
||||
# Database Connection testen
|
||||
docker compose -f docker-compose.production.yml exec php \
|
||||
php -r "new PDO('mysql:host=db;dbname=app_production', 'app_user', '<password>');"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Empfohlener Workflow für dein Projekt
|
||||
|
||||
### Für Initial Setup und kleine Deployments:
|
||||
|
||||
**Verwende Script-Based Deployment**:
|
||||
1. Server Setup (einmalig): Siehe Phase 1
|
||||
2. Initial Deployment: Siehe Phase 2
|
||||
3. Updates: `./scripts/deployment/deploy-production.sh`
|
||||
4. Zero-Downtime: `./scripts/deployment/blue-green-deploy.sh`
|
||||
|
||||
### Für Skalierung und Multiple Environments:
|
||||
|
||||
**Ergänze mit Ansible**:
|
||||
1. Server Provisioning automatisieren
|
||||
2. Multi-Server Deployments orchestrieren
|
||||
3. Konsistente Configuration Management
|
||||
4. Infrastructure as Code
|
||||
|
||||
Siehe nächstes Dokument: [ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md)
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. ✅ Server vorbereiten (Phase 1)
|
||||
2. ✅ Initial Deployment durchführen (Phase 2)
|
||||
3. ✅ Monitoring einrichten (Phase 4)
|
||||
4. 📝 Deployment dokumentieren
|
||||
5. 🔄 Ansible evaluieren (optional, wenn Multi-Server)
|
||||
|
||||
Für detaillierte Ansible-Integration siehe nächstes Dokument!
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,599 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,477 +1,66 @@
|
||||
# Production Deployment Documentation
|
||||
# Deployment Documentation
|
||||
|
||||
Complete documentation for deploying the Custom PHP Framework to production.
|
||||
**Hinweis:** Die Haupt-Deployment-Dokumentation befindet sich jetzt im `deployment/` Ordner.
|
||||
|
||||
---
|
||||
|
||||
## Quick Navigation
|
||||
## 📖 Haupt-Dokumentation
|
||||
|
||||
**New to deployment? Start here:**
|
||||
1. [Quick Start Guide](QUICKSTART.md) - Get running in 30 minutes
|
||||
2. [Deployment Checklist](DEPLOYMENT_CHECKLIST.md) - Printable checklist
|
||||
**Für aktuelle Deployment-Informationen siehe:**
|
||||
|
||||
**Need detailed information?**
|
||||
- [Complete Deployment Workflow](DEPLOYMENT_WORKFLOW.md) - Step-by-step deployment process
|
||||
- [Production Deployment Guide](PRODUCTION_DEPLOYMENT.md) - Comprehensive infrastructure guide
|
||||
- [Production Logging](production-logging.md) - Logging configuration and best practices
|
||||
|
||||
**Want automation?**
|
||||
- [Ansible Deployment](ANSIBLE_DEPLOYMENT.md) - Infrastructure as Code with Ansible
|
||||
|
||||
**Need secure access?**
|
||||
- [WireGuard VPN Setup](WIREGUARD-SETUP.md) - Secure VPN access to production services
|
||||
- **[deployment/README.md](../../deployment/README.md)** - Haupt-Deployment-Dokumentation
|
||||
- **[deployment/QUICK_START.md](../../deployment/QUICK_START.md)** - Schnellstart-Guide
|
||||
- **[deployment/DEPLOYMENT_COMMANDS.md](../../deployment/DEPLOYMENT_COMMANDS.md)** - Command-Referenz
|
||||
- **[deployment/CODE_CHANGE_WORKFLOW.md](../../deployment/CODE_CHANGE_WORKFLOW.md)** - Code-Deployment-Workflow
|
||||
|
||||
---
|
||||
|
||||
## Documentation Structure
|
||||
## 📚 Spezifische Themen-Dokumentation
|
||||
|
||||
### 1. [QUICKSTART.md](QUICKSTART.md)
|
||||
**Best for**: First-time deployment, getting started quickly
|
||||
Die folgenden Dokumente behandeln spezifische Deployment-Themen:
|
||||
|
||||
**Content**:
|
||||
- 10-step deployment process (~30 minutes)
|
||||
- Minimal configuration required
|
||||
- Immediate verification steps
|
||||
- Basic troubleshooting
|
||||
### VPN & Security
|
||||
- **[WIREGUARD-SETUP.md](WIREGUARD-SETUP.md)** - WireGuard VPN Setup (komplett)
|
||||
- **[WIREGUARD-FUTURE-SECURITY.md](WIREGUARD-FUTURE-SECURITY.md)** - Zukünftige Security-Überlegungen
|
||||
- **[PRODUCTION-SECURITY-UPDATES.md](PRODUCTION-SECURITY-UPDATES.md)** - Security-Updates
|
||||
|
||||
**Use when**: You want to get the application running in production as fast as possible.
|
||||
### Configuration & Setup
|
||||
- **[database-migration-strategy.md](database-migration-strategy.md)** - Database Migration Strategy
|
||||
- **[logging-configuration.md](logging-configuration.md)** - Logging Configuration
|
||||
- **[production-logging.md](production-logging.md)** - Production Logging Best Practices
|
||||
- **[secrets-management.md](secrets-management.md)** - Secrets Management mit Vault
|
||||
- **[ssl-setup.md](ssl-setup.md)** - SSL/TLS Setup mit Let's Encrypt
|
||||
- **[SSL-PRODUCTION-SETUP.md](SSL-PRODUCTION-SETUP.md)** - Production SSL Setup
|
||||
- **[env-production-template.md](env-production-template.md)** - Environment Template
|
||||
- **[production-prerequisites.md](production-prerequisites.md)** - Production Prerequisites
|
||||
|
||||
### Automation (Veraltet - siehe deployment/ansible)
|
||||
- **[ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md)** - ⚠️ Veraltet, siehe `deployment/ansible/README.md`
|
||||
- **[deployment-automation.md](deployment-automation.md)** - ⚠️ Veraltet, siehe `deployment/ansible/`
|
||||
|
||||
---
|
||||
|
||||
### 2. [DEPLOYMENT_CHECKLIST.md](DEPLOYMENT_CHECKLIST.md)
|
||||
**Best for**: Ensuring nothing is missed, compliance verification
|
||||
## 🚀 Schnellstart
|
||||
|
||||
**Content**:
|
||||
- Pre-deployment checklist
|
||||
- Step-by-step deployment verification
|
||||
- Post-deployment security hardening
|
||||
- Maintenance schedules (weekly, monthly, quarterly)
|
||||
- Emergency contacts template
|
||||
- Deployment sign-off form
|
||||
**Für aktuelle Deployment-Informationen:**
|
||||
|
||||
**Use when**: You want a printable, check-off-items-as-you-go guide.
|
||||
|
||||
---
|
||||
|
||||
### 3. [DEPLOYMENT_WORKFLOW.md](DEPLOYMENT_WORKFLOW.md)
|
||||
**Best for**: Understanding the complete deployment lifecycle
|
||||
|
||||
**Content**:
|
||||
- Phase 1: Initial Server Setup (one-time)
|
||||
- Phase 2: Initial Deployment
|
||||
- Phase 3: Ongoing Deployment (updates)
|
||||
- Phase 4: Monitoring Setup
|
||||
- Two deployment options: Manual/Script-Based and Ansible-Based
|
||||
- Automated deployment scripts
|
||||
- Zero-downtime deployment
|
||||
- Rollback procedures
|
||||
|
||||
**Use when**: You need detailed explanations of each deployment phase or want to understand deployment options.
|
||||
|
||||
---
|
||||
|
||||
### 4. [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md)
|
||||
**Best for**: Comprehensive infrastructure reference
|
||||
|
||||
**Content**:
|
||||
- Complete infrastructure setup
|
||||
- SSL/TLS configuration with Let's Encrypt
|
||||
- Secrets management with Vault
|
||||
- Environment configuration
|
||||
- Docker deployment
|
||||
- Database migrations
|
||||
- Monitoring and health checks (all endpoints documented)
|
||||
- Logging configuration
|
||||
- Security considerations
|
||||
- Troubleshooting guide
|
||||
- Maintenance procedures
|
||||
|
||||
**Use when**: You need deep technical details about any production infrastructure component.
|
||||
|
||||
---
|
||||
|
||||
### 5. [production-logging.md](production-logging.md)
|
||||
**Best for**: Production logging configuration and optimization
|
||||
|
||||
**Content**:
|
||||
- ProductionLogConfig options (production, highPerformance, withAggregation, debug, staging)
|
||||
- Environment-based configuration
|
||||
- Log rotation and retention policies
|
||||
- Structured JSON log format
|
||||
- Metrics and monitoring integration
|
||||
- Performance tuning (buffer sizes, sampling rates, aggregation)
|
||||
- Troubleshooting guides
|
||||
- Best practices
|
||||
|
||||
**Use when**: You need to configure or troubleshoot production logging.
|
||||
|
||||
---
|
||||
|
||||
### 6. [ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md)
|
||||
**Best for**: Automated, multi-server deployments
|
||||
|
||||
**Content**:
|
||||
- Complete Ansible project structure
|
||||
- Ansible roles (common, docker, ssl, application)
|
||||
- Playbooks (site.yml, deploy.yml, rollback.yml, provision.yml)
|
||||
- Ansible Vault for secrets
|
||||
- CI/CD integration (GitHub Actions)
|
||||
- Comparison: Script-Based vs Ansible
|
||||
- Hybrid approach recommendation
|
||||
|
||||
**Use when**: You're scaling to multiple servers or want infrastructure as code.
|
||||
|
||||
---
|
||||
|
||||
### 7. [WIREGUARD-SETUP.md](WIREGUARD-SETUP.md)
|
||||
**Best for**: Secure VPN access to production services
|
||||
|
||||
**Content**:
|
||||
- Complete WireGuard VPN setup guide
|
||||
- Server installation via Ansible
|
||||
- Client configuration and management
|
||||
- Connection testing and troubleshooting
|
||||
- Security best practices
|
||||
- Monitoring and maintenance
|
||||
|
||||
**Use when**: You need secure access to internal services (Prometheus, Grafana, Portainer) or want to restrict access via VPN.
|
||||
|
||||
---
|
||||
|
||||
## Which Guide Should I Use?
|
||||
|
||||
### Scenario 1: First-Time Deployment
|
||||
**Path**: QUICKSTART.md → DEPLOYMENT_CHECKLIST.md
|
||||
|
||||
1. Follow [QUICKSTART.md](QUICKSTART.md) for initial deployment
|
||||
2. Use [DEPLOYMENT_CHECKLIST.md](DEPLOYMENT_CHECKLIST.md) to verify everything
|
||||
3. Keep [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md) handy for troubleshooting
|
||||
|
||||
**Time Required**: ~1 hour
|
||||
|
||||
---
|
||||
|
||||
### Scenario 2: Enterprise Deployment
|
||||
**Path**: PRODUCTION_DEPLOYMENT.md → ANSIBLE_DEPLOYMENT.md → DEPLOYMENT_CHECKLIST.md
|
||||
|
||||
1. Review [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md) for infrastructure understanding
|
||||
2. Implement with [ANSIBLE_DEPLOYMENT.md](ANSIBLE_DEPLOYMENT.md) for automation
|
||||
3. Verify with [DEPLOYMENT_CHECKLIST.md](DEPLOYMENT_CHECKLIST.md)
|
||||
|
||||
**Time Required**: ~4 hours (initial setup), ~30 minutes (ongoing deployments)
|
||||
|
||||
---
|
||||
|
||||
### Scenario 3: Single Server, Team Collaboration
|
||||
**Path**: DEPLOYMENT_WORKFLOW.md → DEPLOYMENT_CHECKLIST.md
|
||||
|
||||
1. Follow [DEPLOYMENT_WORKFLOW.md](DEPLOYMENT_WORKFLOW.md) for comprehensive process
|
||||
2. Use automated scripts (deploy-production.sh)
|
||||
3. Verify with [DEPLOYMENT_CHECKLIST.md](DEPLOYMENT_CHECKLIST.md)
|
||||
|
||||
**Time Required**: ~2 hours
|
||||
|
||||
---
|
||||
|
||||
### Scenario 4: Logging Issues
|
||||
**Path**: production-logging.md
|
||||
|
||||
1. Consult [production-logging.md](production-logging.md) for logging configuration
|
||||
2. Check troubleshooting section
|
||||
3. Adjust ProductionLogConfig based on needs
|
||||
|
||||
**Time Required**: ~30 minutes
|
||||
|
||||
---
|
||||
|
||||
### Scenario 5: Adding Monitoring
|
||||
**Path**: PRODUCTION_DEPLOYMENT.md (Monitoring section)
|
||||
|
||||
1. Jump to Monitoring section in [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md)
|
||||
2. Follow Prometheus/Grafana setup
|
||||
3. Configure alerts
|
||||
|
||||
**Time Required**: ~1 hour
|
||||
|
||||
---
|
||||
|
||||
## Deployment Methods Comparison
|
||||
|
||||
| Feature | Quick Start | Script-Based | Ansible |
|
||||
|---------|-------------|--------------|---------|
|
||||
| **Setup Time** | 30 min | 2 hours | 4 hours |
|
||||
| **Ongoing Deployment** | 15 min | 10 min | 5 min |
|
||||
| **Multi-Server** | Manual | Manual | Automated |
|
||||
| **Rollback** | Manual | Script | Automated |
|
||||
| **Team Collaboration** | Docs | Scripts + Docs | Playbooks |
|
||||
| **Infrastructure as Code** | No | Partial | Yes |
|
||||
| **Idempotency** | No | Partial | Yes |
|
||||
| **Best For** | Single server, quick start | Single server, repeatable | Multiple servers, scaling |
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites Summary
|
||||
|
||||
All deployment methods require:
|
||||
|
||||
### Server Requirements
|
||||
- Ubuntu 22.04+ (or Debian 11+)
|
||||
- 4GB RAM minimum (8GB recommended)
|
||||
- 40GB disk space minimum
|
||||
- Root or sudo access
|
||||
|
||||
### Network Requirements
|
||||
- Domain name configured
|
||||
- DNS pointing to server IP
|
||||
- Ports 22, 80, 443 accessible
|
||||
- Static IP address recommended
|
||||
|
||||
### Tools Required
|
||||
- SSH client
|
||||
- Git
|
||||
- Text editor (nano, vim, or VS Code with Remote SSH)
|
||||
|
||||
### Knowledge Requirements
|
||||
- Basic Linux command line
|
||||
- SSH and file permissions
|
||||
- Docker basics
|
||||
- DNS and domain configuration
|
||||
- (Optional) Ansible for automation
|
||||
|
||||
---
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Initial Deployment
|
||||
```bash
|
||||
# Follow Quick Start Guide
|
||||
cat docs/deployment/QUICKSTART.md
|
||||
# Haupt-Dokumentation
|
||||
cat deployment/README.md
|
||||
|
||||
# Verify with checklist
|
||||
cat docs/deployment/DEPLOYMENT_CHECKLIST.md
|
||||
# Schnellstart
|
||||
cat deployment/QUICK_START.md
|
||||
|
||||
# Commands
|
||||
cat deployment/DEPLOYMENT_COMMANDS.md
|
||||
```
|
||||
|
||||
### Deploy Update
|
||||
```bash
|
||||
# Manual method
|
||||
cd /home/appuser/app
|
||||
git pull origin main
|
||||
docker compose -f docker-compose.production.yml build
|
||||
docker compose -f docker-compose.production.yml up -d
|
||||
php console.php db:migrate
|
||||
|
||||
# Automated script method
|
||||
./scripts/deployment/deploy-production.sh
|
||||
|
||||
# Zero-downtime method
|
||||
./scripts/deployment/blue-green-deploy.sh
|
||||
```
|
||||
|
||||
### Rollback
|
||||
```bash
|
||||
# Manual rollback (see DEPLOYMENT_WORKFLOW.md)
|
||||
docker compose -f docker-compose.old.yml up -d
|
||||
php console.php db:rollback 1
|
||||
|
||||
# Automated rollback
|
||||
./scripts/deployment/blue-green-rollback.sh
|
||||
```
|
||||
|
||||
### Health Check
|
||||
```bash
|
||||
# Quick health check
|
||||
curl -f https://yourdomain.com/health/summary
|
||||
|
||||
# Detailed health check
|
||||
curl -f https://yourdomain.com/health/detailed | jq
|
||||
|
||||
# Specific category
|
||||
curl -f https://yourdomain.com/health/category/database
|
||||
```
|
||||
|
||||
### View Logs
|
||||
```bash
|
||||
# Application logs
|
||||
docker compose -f docker-compose.production.yml logs -f php
|
||||
|
||||
# System logs
|
||||
tail -f /var/log/app/app.log
|
||||
|
||||
# Nginx logs
|
||||
tail -f /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
### Database Backup
|
||||
```bash
|
||||
# Manual backup
|
||||
docker compose exec database mysqldump -u app_user -p app_production > backup.sql
|
||||
|
||||
# Automated backup (configured in QUICKSTART.md)
|
||||
/home/appuser/backup-production.sh
|
||||
```
|
||||
|
||||
### SSL Certificate Renewal
|
||||
```bash
|
||||
# Test renewal
|
||||
certbot renew --dry-run
|
||||
|
||||
# Force renewal
|
||||
certbot renew --force-renewal
|
||||
|
||||
# Automatic renewal is configured via cron/systemd timer
|
||||
```
|
||||
**Für spezifische Themen:**
|
||||
- VPN Setup: `docs/deployment/WIREGUARD-SETUP.md`
|
||||
- Database Migrations: `docs/deployment/database-migration-strategy.md`
|
||||
- Logging: `docs/deployment/production-logging.md`
|
||||
- SSL Setup: `docs/deployment/ssl-setup.md`
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Quick Reference
|
||||
|
||||
### Issue: Containers won't start
|
||||
**Solution**: Check logs
|
||||
```bash
|
||||
docker compose -f docker-compose.production.yml logs php
|
||||
```
|
||||
|
||||
**Common causes**: Database credentials, port conflicts, permissions
|
||||
|
||||
**Full guide**: [PRODUCTION_DEPLOYMENT.md - Troubleshooting](PRODUCTION_DEPLOYMENT.md#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
### Issue: Health checks failing
|
||||
**Solution**: Check specific health check
|
||||
```bash
|
||||
curl http://localhost/health/category/database
|
||||
```
|
||||
|
||||
**Common causes**: Database not migrated, cache not writable, queue not running
|
||||
|
||||
**Full guide**: [DEPLOYMENT_WORKFLOW.md - Troubleshooting](DEPLOYMENT_WORKFLOW.md#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
### Issue: SSL certificate problems
|
||||
**Solution**: Verify certificate
|
||||
```bash
|
||||
openssl x509 -in /etc/letsencrypt/live/yourdomain.com/fullchain.pem -noout -dates
|
||||
```
|
||||
|
||||
**Common causes**: DNS not propagated, port 80 blocked, wrong domain
|
||||
|
||||
**Full guide**: [PRODUCTION_DEPLOYMENT.md - SSL/TLS](PRODUCTION_DEPLOYMENT.md#ssltls-configuration)
|
||||
|
||||
---
|
||||
|
||||
### Issue: Application errors
|
||||
**Solution**: Check application logs
|
||||
```bash
|
||||
docker compose -f docker-compose.production.yml logs -f php
|
||||
tail -f /var/log/app/app.log
|
||||
```
|
||||
|
||||
**Common causes**: Environment configuration, missing migrations, permission issues
|
||||
|
||||
**Full guide**: [production-logging.md - Troubleshooting](production-logging.md#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
All deployment methods include security best practices:
|
||||
|
||||
- ✅ HTTPS enforced (SSL/TLS)
|
||||
- ✅ Firewall configured (UFW)
|
||||
- ✅ SSH key-only authentication
|
||||
- ✅ Fail2Ban for intrusion prevention
|
||||
- ✅ Security headers (CSP, HSTS, X-Frame-Options)
|
||||
- ✅ CSRF protection
|
||||
- ✅ Rate limiting
|
||||
- ✅ WAF (Web Application Firewall)
|
||||
- ✅ Vault for secrets management
|
||||
- ✅ Regular security updates
|
||||
|
||||
**Detailed security guide**: [PRODUCTION_DEPLOYMENT.md - Security](PRODUCTION_DEPLOYMENT.md#security-considerations)
|
||||
|
||||
---
|
||||
|
||||
## Monitoring and Health Checks
|
||||
|
||||
### Available Endpoints
|
||||
|
||||
```
|
||||
GET /health/summary - Quick health summary
|
||||
GET /health/detailed - Full health report with all checks
|
||||
GET /health/checks - List registered health checks
|
||||
GET /health/category/{cat} - Health checks by category
|
||||
|
||||
GET /metrics - Prometheus metrics
|
||||
GET /metrics/json - JSON metrics
|
||||
```
|
||||
|
||||
### Health Check Categories
|
||||
- `DATABASE` - Database connectivity and performance
|
||||
- `CACHE` - Cache system health (Redis/File)
|
||||
- `SECURITY` - SSL certificates, rate limiting, CSRF
|
||||
- `INFRASTRUCTURE` - Disk space, memory, queue status
|
||||
- `EXTERNAL` - External service connectivity
|
||||
|
||||
**Full monitoring guide**: [PRODUCTION_DEPLOYMENT.md - Monitoring](PRODUCTION_DEPLOYMENT.md#monitoring-and-health-checks)
|
||||
|
||||
---
|
||||
|
||||
## Support and Resources
|
||||
|
||||
### Internal Documentation
|
||||
- [Framework Guidelines](../claude/guidelines.md)
|
||||
- [Security Patterns](../claude/security-patterns.md)
|
||||
- [Database Patterns](../claude/database-patterns.md)
|
||||
- [Error Handling](../claude/error-handling.md)
|
||||
|
||||
### External Resources
|
||||
- [Docker Documentation](https://docs.docker.com/)
|
||||
- [Let's Encrypt Documentation](https://letsencrypt.org/docs/)
|
||||
- [Nginx Documentation](https://nginx.org/en/docs/)
|
||||
- [Ansible Documentation](https://docs.ansible.com/) (for automation)
|
||||
|
||||
### Getting Help
|
||||
|
||||
1. **Check documentation** (this directory)
|
||||
2. **Review application logs** (`docker compose logs`)
|
||||
3. **Check health endpoints** (`/health/detailed`)
|
||||
4. **Review metrics** (`/metrics`)
|
||||
5. **Consult troubleshooting guides** (in each document)
|
||||
|
||||
---
|
||||
|
||||
## Contribution
|
||||
|
||||
This documentation should be updated after each deployment to reflect:
|
||||
- Lessons learned
|
||||
- Process improvements
|
||||
- Common issues encountered
|
||||
- New best practices discovered
|
||||
|
||||
**Deployment feedback template**: See [DEPLOYMENT_CHECKLIST.md - Continuous Improvement](DEPLOYMENT_CHECKLIST.md#continuous-improvement)
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Date | Changes | Author |
|
||||
|---------|------|---------|--------|
|
||||
| 1.0 | 2025-01-15 | Initial comprehensive deployment documentation | System |
|
||||
| | | Complete with Quick Start, Workflow, Ansible, Checklists | |
|
||||
|
||||
---
|
||||
|
||||
**Quick Links**:
|
||||
- [Quick Start](QUICKSTART.md) - Fastest path to production
|
||||
- [Checklist](DEPLOYMENT_CHECKLIST.md) - Ensure nothing is missed
|
||||
- [Complete Workflow](DEPLOYMENT_WORKFLOW.md) - Detailed deployment process
|
||||
- [Production Guide](PRODUCTION_DEPLOYMENT.md) - Comprehensive reference
|
||||
- [Logging Guide](production-logging.md) - Production logging configuration
|
||||
- [Ansible Guide](ANSIBLE_DEPLOYMENT.md) - Infrastructure automation
|
||||
- [WireGuard VPN](WIREGUARD-SETUP.md) - Secure VPN access to production
|
||||
|
||||
---
|
||||
|
||||
**Ready to deploy? Start with [QUICKSTART.md](QUICKSTART.md) →**
|
||||
**Haupt-Deployment-Dokumentation:** Siehe [deployment/](../../deployment/) Ordner
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# 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
|
||||
|
||||
@@ -1,711 +0,0 @@
|
||||
# Production Docker Compose Configuration
|
||||
|
||||
Production Docker Compose configuration mit Sicherheits-Härtung, Performance-Optimierung und Monitoring für das Custom PHP Framework.
|
||||
|
||||
## Übersicht
|
||||
|
||||
Das Projekt verwendet Docker Compose Overlay-Pattern:
|
||||
- **Base**: `docker-compose.yml` - Entwicklungsumgebung
|
||||
- **Production**: `docker-compose.production.yml` - Production-spezifische Overrides
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Production-Stack starten
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
--env-file .env.production \
|
||||
up -d
|
||||
|
||||
# Mit Build (bei Änderungen)
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
--env-file .env.production \
|
||||
up -d --build
|
||||
|
||||
# Stack stoppen
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
down
|
||||
|
||||
# Logs anzeigen
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
logs -f [service]
|
||||
|
||||
# Service Health Check
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
ps
|
||||
```
|
||||
|
||||
## Production Overrides
|
||||
|
||||
### 1. Web (Nginx) Service
|
||||
|
||||
**Restart Policy**:
|
||||
```yaml
|
||||
restart: always # Automatischer Neustart bei Fehlern
|
||||
```
|
||||
|
||||
**SSL/TLS Configuration**:
|
||||
```yaml
|
||||
volumes:
|
||||
- certbot-conf:/etc/letsencrypt:ro
|
||||
- certbot-www:/var/www/certbot:ro
|
||||
```
|
||||
- Let's Encrypt Zertifikate via Certbot
|
||||
- Read-only Mounts für Sicherheit
|
||||
|
||||
**Health Checks**:
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "https://localhost/health"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
```
|
||||
- HTTPS Health Check auf `/health` Endpoint
|
||||
- 15 Sekunden Intervall für schnelle Fehler-Erkennung
|
||||
- 5 Retries vor Service-Nestart
|
||||
|
||||
**Resource Limits**:
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
```
|
||||
- Nginx ist lightweight, moderate Limits
|
||||
|
||||
**Logging**:
|
||||
```yaml
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "5"
|
||||
compress: "true"
|
||||
labels: "service,environment"
|
||||
```
|
||||
- JSON-Format für Log-Aggregation (ELK Stack kompatibel)
|
||||
- 10MB pro Datei, 5 Dateien = 50MB total
|
||||
- Komprimierte Rotation
|
||||
|
||||
### 2. PHP Service
|
||||
|
||||
**Restart Policy**:
|
||||
```yaml
|
||||
restart: always
|
||||
```
|
||||
|
||||
**Build Configuration**:
|
||||
```yaml
|
||||
build:
|
||||
args:
|
||||
- ENV=production
|
||||
- COMPOSER_INSTALL_FLAGS=--no-dev --optimize-autoloader --classmap-authoritative
|
||||
```
|
||||
- `--no-dev`: Keine Development-Dependencies
|
||||
- `--optimize-autoloader`: PSR-4 Optimization
|
||||
- `--classmap-authoritative`: Keine Filesystem-Lookups (Performance)
|
||||
|
||||
**Environment**:
|
||||
```yaml
|
||||
environment:
|
||||
- APP_ENV=production
|
||||
- APP_DEBUG=false # DEBUG AUS in Production!
|
||||
- PHP_MEMORY_LIMIT=512M
|
||||
- PHP_MAX_EXECUTION_TIME=30
|
||||
- XDEBUG_MODE=off # Xdebug aus für Performance
|
||||
```
|
||||
|
||||
**Health Checks**:
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "php-fpm-healthcheck"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
```
|
||||
- PHP-FPM Health Check via Custom Script
|
||||
- Schnelles Failure-Detection
|
||||
|
||||
**Resource Limits**:
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '1.0'
|
||||
```
|
||||
- PHP benötigt mehr Memory als Nginx
|
||||
- 2 CPUs für parallele Request-Verarbeitung
|
||||
|
||||
**Volumes**:
|
||||
```yaml
|
||||
volumes:
|
||||
- storage-logs:/var/www/html/storage/logs:rw
|
||||
- storage-cache:/var/www/html/storage/cache:rw
|
||||
- storage-queue:/var/www/html/storage/queue:rw
|
||||
- storage-discovery:/var/www/html/storage/discovery:rw
|
||||
- storage-uploads:/var/www/html/storage/uploads:rw
|
||||
```
|
||||
- Nur notwendige Docker Volumes
|
||||
- **KEINE Host-Mounts** für Sicherheit
|
||||
- Application Code im Image (nicht gemountet)
|
||||
|
||||
### 3. Database (PostgreSQL 16) Service
|
||||
|
||||
**Restart Policy**:
|
||||
```yaml
|
||||
restart: always
|
||||
```
|
||||
|
||||
**Production Configuration**:
|
||||
```yaml
|
||||
volumes:
|
||||
- db_data:/var/lib/postgresql/data
|
||||
- ./docker/postgres/postgresql.production.conf:/etc/postgresql/postgresql.conf:ro
|
||||
- ./docker/postgres/init:/docker-entrypoint-initdb.d:ro
|
||||
```
|
||||
- Production-optimierte `postgresql.production.conf`
|
||||
- Init-Scripts für Schema-Setup
|
||||
|
||||
**Resource Limits**:
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
```
|
||||
- PostgreSQL benötigt Memory für `shared_buffers` (2GB in Config)
|
||||
- 2 CPUs für parallele Query-Verarbeitung
|
||||
|
||||
**Health Checks**:
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-postgres} -d ${DB_DATABASE:-michaelschiemer}"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
```
|
||||
- `pg_isready` für schnelle Connection-Prüfung
|
||||
- 10 Sekunden Intervall (häufiger als andere Services)
|
||||
|
||||
**Logging**:
|
||||
```yaml
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "20m" # Größere Log-Dateien für PostgreSQL
|
||||
max-file: "10"
|
||||
compress: "true"
|
||||
```
|
||||
- PostgreSQL loggt mehr (Slow Queries, Checkpoints, etc.)
|
||||
- 20MB pro Datei, 10 Dateien = 200MB total
|
||||
|
||||
### 4. Redis Service
|
||||
|
||||
**Restart Policy**:
|
||||
```yaml
|
||||
restart: always
|
||||
```
|
||||
|
||||
**Resource Limits**:
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 256M
|
||||
cpus: '0.5'
|
||||
```
|
||||
- Redis ist Memory-basiert, moderate Limits
|
||||
|
||||
**Health Checks**:
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
```
|
||||
- `redis-cli ping` für Connection-Check
|
||||
- Schneller Start (10s start_period)
|
||||
|
||||
### 5. Queue Worker Service
|
||||
|
||||
**Restart Policy**:
|
||||
```yaml
|
||||
restart: always
|
||||
```
|
||||
|
||||
**Environment**:
|
||||
```yaml
|
||||
environment:
|
||||
- APP_ENV=production
|
||||
- WORKER_DEBUG=false
|
||||
- WORKER_SLEEP_TIME=100000
|
||||
- WORKER_MAX_JOBS=10000
|
||||
```
|
||||
- Production-Modus ohne Debug
|
||||
- 10,000 Jobs pro Worker-Lifecycle
|
||||
|
||||
**Resource Limits**:
|
||||
```yaml
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
replicas: 2 # 2 Worker-Instanzen
|
||||
```
|
||||
- Worker benötigen Memory für Job-Processing
|
||||
- **2 Replicas** für Parallelität
|
||||
|
||||
**Graceful Shutdown**:
|
||||
```yaml
|
||||
stop_grace_period: 60s
|
||||
```
|
||||
- 60 Sekunden für Job-Completion vor Shutdown
|
||||
- Verhindert Job-Abbrüche
|
||||
|
||||
**Logging**:
|
||||
```yaml
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "20m"
|
||||
max-file: "10"
|
||||
compress: "true"
|
||||
```
|
||||
- Worker loggen ausführlich (Job-Start, Completion, Errors)
|
||||
- 200MB total Log-Storage
|
||||
|
||||
### 6. Certbot Service
|
||||
|
||||
**Restart Policy**:
|
||||
```yaml
|
||||
restart: always
|
||||
```
|
||||
|
||||
**Auto-Renewal**:
|
||||
```yaml
|
||||
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot --quiet; sleep 12h & wait $${!}; done;'"
|
||||
```
|
||||
- Automatische Erneuerung alle 12 Stunden
|
||||
- Webroot-Challenge über Nginx
|
||||
|
||||
**Volumes**:
|
||||
```yaml
|
||||
volumes:
|
||||
- certbot-conf:/etc/letsencrypt
|
||||
- certbot-www:/var/www/certbot
|
||||
- certbot-logs:/var/log/letsencrypt
|
||||
```
|
||||
- Zertifikate werden mit Nginx geteilt
|
||||
|
||||
## Network Configuration
|
||||
|
||||
**Security Isolation**:
|
||||
```yaml
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
backend:
|
||||
driver: bridge
|
||||
internal: true # Backend network is internal (no internet access)
|
||||
cache:
|
||||
driver: bridge
|
||||
internal: true # Cache network is internal
|
||||
```
|
||||
|
||||
**Network-Segmentierung**:
|
||||
- **Frontend**: Nginx, Certbot (Internet-Zugriff)
|
||||
- **Backend**: PHP, PostgreSQL, Queue Worker (KEIN Internet-Zugriff)
|
||||
- **Cache**: Redis (KEIN Internet-Zugriff)
|
||||
|
||||
**Security Benefits**:
|
||||
- Backend Services können nicht nach außen kommunizieren
|
||||
- Verhindert Data Exfiltration bei Compromise
|
||||
- Zero-Trust Network Architecture
|
||||
|
||||
## Volumes Configuration
|
||||
|
||||
**SSL/TLS Volumes**:
|
||||
```yaml
|
||||
certbot-conf:
|
||||
driver: local
|
||||
certbot-www:
|
||||
driver: local
|
||||
certbot-logs:
|
||||
driver: local
|
||||
```
|
||||
|
||||
**Application Storage Volumes**:
|
||||
```yaml
|
||||
storage-logs:
|
||||
driver: local
|
||||
storage-cache:
|
||||
driver: local
|
||||
storage-queue:
|
||||
driver: local
|
||||
storage-discovery:
|
||||
driver: local
|
||||
storage-uploads:
|
||||
driver: local
|
||||
```
|
||||
|
||||
**Database Volume**:
|
||||
```yaml
|
||||
db_data:
|
||||
driver: local
|
||||
# Optional: External volume for backups
|
||||
# driver_opts:
|
||||
# type: none
|
||||
# o: bind
|
||||
# device: /mnt/db-backups/michaelschiemer-prod
|
||||
```
|
||||
|
||||
**Volume Best Practices**:
|
||||
- Alle Volumes sind `driver: local` (nicht Host-Mounts)
|
||||
- Für Backups: Optional External Volume für Database
|
||||
- Keine Development-Host-Mounts in Production
|
||||
|
||||
## Logging Strategy
|
||||
|
||||
**JSON Logging** für alle Services:
|
||||
```yaml
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m" # Service-abhängig
|
||||
max-file: "5" # Service-abhängig
|
||||
compress: "true"
|
||||
labels: "service,environment"
|
||||
```
|
||||
|
||||
**Log Rotation**:
|
||||
| Service | Max Size | Max Files | Total Storage |
|
||||
|---------|----------|-----------|---------------|
|
||||
| Nginx | 10MB | 5 | 50MB |
|
||||
| PHP | 10MB | 10 | 100MB |
|
||||
| PostgreSQL | 20MB | 10 | 200MB |
|
||||
| Redis | 10MB | 5 | 50MB |
|
||||
| Queue Worker | 20MB | 10 | 200MB |
|
||||
| Certbot | 5MB | 3 | 15MB |
|
||||
| **TOTAL** | | | **615MB** |
|
||||
|
||||
**Log Aggregation**:
|
||||
- JSON-Format für ELK Stack (Elasticsearch, Logstash, Kibana)
|
||||
- Labels für Service-Identifikation
|
||||
- Komprimierte Log-Files für Storage-Effizienz
|
||||
|
||||
## Resource Allocation
|
||||
|
||||
**Total Resource Requirements**:
|
||||
|
||||
| Service | Memory Limit | Memory Reservation | CPU Limit | CPU Reservation |
|
||||
|---------|--------------|-------------------|-----------|-----------------|
|
||||
| Nginx | 512M | 256M | 1.0 | 0.5 |
|
||||
| PHP | 1G | 512M | 2.0 | 1.0 |
|
||||
| PostgreSQL | 2G | 1G | 2.0 | 1.0 |
|
||||
| Redis | 512M | 256M | 1.0 | 0.5 |
|
||||
| Queue Worker (x2) | 4G | 2G | 4.0 | 2.0 |
|
||||
| **TOTAL** | **8GB** | **4GB** | **10 CPUs** | **5 CPUs** |
|
||||
|
||||
**Server Sizing Recommendations**:
|
||||
- **Minimum**: 8GB RAM, 4 CPUs (Resource Limits)
|
||||
- **Recommended**: 16GB RAM, 8 CPUs (Headroom für OS und Spikes)
|
||||
- **Optimal**: 32GB RAM, 16 CPUs (Production mit Monitoring)
|
||||
|
||||
## Health Checks
|
||||
|
||||
**Health Check Strategy**:
|
||||
|
||||
| Service | Endpoint | Interval | Timeout | Retries | Start Period |
|
||||
|---------|----------|----------|---------|---------|--------------|
|
||||
| Nginx | HTTPS /health | 15s | 5s | 5 | 30s |
|
||||
| PHP | php-fpm-healthcheck | 15s | 5s | 5 | 30s |
|
||||
| PostgreSQL | pg_isready | 10s | 3s | 5 | 30s |
|
||||
| Redis | redis-cli ping | 10s | 3s | 5 | 10s |
|
||||
|
||||
**Health Check Benefits**:
|
||||
- Automatische Service-Recovery bei Failures
|
||||
- Docker orchestriert Neustart nur bei unhealthy Services
|
||||
- Health-Status via `docker-compose ps`
|
||||
|
||||
## Deployment Workflow
|
||||
|
||||
### Initial Deployment
|
||||
|
||||
```bash
|
||||
# 1. Server vorbereiten (siehe production-prerequisites.md)
|
||||
|
||||
# 2. .env.production konfigurieren (siehe env-production-template.md)
|
||||
|
||||
# 3. Build und Deploy
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
--env-file .env.production \
|
||||
up -d --build
|
||||
|
||||
# 4. SSL Zertifikate initialisieren
|
||||
docker exec php php console.php ssl:init
|
||||
|
||||
# 5. Database Migrationen
|
||||
docker exec php php console.php db:migrate
|
||||
|
||||
# 6. Health Checks verifizieren
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
ps
|
||||
```
|
||||
|
||||
### Rolling Update (Zero-Downtime)
|
||||
|
||||
```bash
|
||||
# 1. Neue Version pullen
|
||||
git pull origin main
|
||||
|
||||
# 2. Build neue Images
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
--env-file .env.production \
|
||||
build --no-cache
|
||||
|
||||
# 3. Rolling Update (Service für Service)
|
||||
# Nginx
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
up -d --no-deps web
|
||||
|
||||
# PHP (nach Nginx)
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
up -d --no-deps php
|
||||
|
||||
# Queue Worker (nach PHP)
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
up -d --no-deps --scale queue-worker=2 queue-worker
|
||||
|
||||
# 4. Health Checks verifizieren
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
ps
|
||||
```
|
||||
|
||||
### Rollback Strategy
|
||||
|
||||
```bash
|
||||
# 1. Previous Git Commit
|
||||
git log --oneline -5
|
||||
git checkout <previous-commit>
|
||||
|
||||
# 2. Rebuild und Deploy
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
--env-file .env.production \
|
||||
up -d --build
|
||||
|
||||
# 3. Database Rollback (wenn nötig)
|
||||
docker exec php php console.php db:rollback 1
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Container Status
|
||||
|
||||
```bash
|
||||
# Status aller Services
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
ps
|
||||
|
||||
# Detaillierte Informationen
|
||||
docker inspect <container-name>
|
||||
```
|
||||
|
||||
### Resource Usage
|
||||
|
||||
```bash
|
||||
# CPU/Memory Usage
|
||||
docker stats
|
||||
|
||||
# Service-spezifisch
|
||||
docker stats php db redis
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
```bash
|
||||
# Alle Logs (Follow)
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
logs -f
|
||||
|
||||
# Service-spezifisch
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
logs -f php
|
||||
|
||||
# Letzte N Zeilen
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
logs --tail=100 php
|
||||
```
|
||||
|
||||
### Health Check Status
|
||||
|
||||
```bash
|
||||
# Health Check Logs
|
||||
docker inspect --format='{{json .State.Health}}' php | jq
|
||||
|
||||
# Health History
|
||||
docker inspect --format='{{range .State.Health.Log}}{{.Start}} {{.ExitCode}} {{.Output}}{{end}}' php
|
||||
```
|
||||
|
||||
## Backup Strategy
|
||||
|
||||
### Database Backup
|
||||
|
||||
```bash
|
||||
# Manual Backup
|
||||
docker exec db pg_dump -U postgres michaelschiemer_prod > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
|
||||
# Automated Backup (Cron)
|
||||
# /etc/cron.daily/postgres-backup
|
||||
#!/bin/bash
|
||||
docker exec db pg_dump -U postgres michaelschiemer_prod | gzip > /mnt/backups/michaelschiemer_$(date +%Y%m%d).sql.gz
|
||||
```
|
||||
|
||||
### Volume Backup
|
||||
|
||||
```bash
|
||||
# Backup all volumes
|
||||
docker run --rm \
|
||||
-v michaelschiemer_db_data:/data:ro \
|
||||
-v $(pwd)/backups:/backup \
|
||||
alpine tar czf /backup/db_data_$(date +%Y%m%d).tar.gz -C /data .
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Service Won't Start
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
logs <service>
|
||||
|
||||
# Check configuration
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
config
|
||||
```
|
||||
|
||||
### Health Check Failing
|
||||
|
||||
```bash
|
||||
# Manual health check
|
||||
docker exec php php-fpm-healthcheck
|
||||
docker exec db pg_isready -U postgres
|
||||
docker exec redis redis-cli ping
|
||||
|
||||
# Check health logs
|
||||
docker inspect --format='{{json .State.Health}}' <container> | jq
|
||||
```
|
||||
|
||||
### Memory Issues
|
||||
|
||||
```bash
|
||||
# Check memory usage
|
||||
docker stats
|
||||
|
||||
# Increase limits in docker-compose.production.yml
|
||||
# Then restart service
|
||||
docker-compose -f docker-compose.yml \
|
||||
-f docker-compose.production.yml \
|
||||
up -d --no-deps <service>
|
||||
```
|
||||
|
||||
### Network Issues
|
||||
|
||||
```bash
|
||||
# Check networks
|
||||
docker network ls
|
||||
docker network inspect michaelschiemer-prod_backend
|
||||
|
||||
# Test connectivity
|
||||
docker exec php ping db
|
||||
docker exec php nc -zv db 5432
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### 1. Network Isolation
|
||||
- ✅ Backend network is internal (no internet access)
|
||||
- ✅ Cache network is internal
|
||||
- ✅ Only frontend services expose ports
|
||||
|
||||
### 2. Volume Security
|
||||
- ✅ No host mounts (application code in image)
|
||||
- ✅ Read-only mounts where possible (SSL certificates)
|
||||
- ✅ Named Docker volumes (managed by Docker)
|
||||
|
||||
### 3. Secrets Management
|
||||
- ✅ Use `.env.production` (not committed to git)
|
||||
- ✅ Use Vault for sensitive data
|
||||
- ✅ No secrets in docker-compose files
|
||||
|
||||
### 4. Resource Limits
|
||||
- ✅ All services have memory limits (prevent OOM)
|
||||
- ✅ CPU limits prevent resource starvation
|
||||
- ✅ Restart policies for automatic recovery
|
||||
|
||||
### 5. Logging
|
||||
- ✅ JSON logging for security monitoring
|
||||
- ✅ Log rotation prevents disk exhaustion
|
||||
- ✅ Compressed logs for storage efficiency
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always use `.env.production`** - Never commit production secrets
|
||||
2. **Test updates in staging first** - Use same docker-compose setup
|
||||
3. **Monitor resource usage** - Adjust limits based on metrics
|
||||
4. **Regular backups** - Automate database and volume backups
|
||||
5. **Health checks** - Ensure all services have working health checks
|
||||
6. **Log aggregation** - Send logs to centralized logging system (ELK)
|
||||
7. **SSL renewal** - Monitor Certbot logs for renewal issues
|
||||
8. **Security updates** - Regularly update Docker images
|
||||
|
||||
## See Also
|
||||
|
||||
- **Prerequisites**: `docs/deployment/production-prerequisites.md`
|
||||
- **Environment Configuration**: `docs/deployment/env-production-template.md`
|
||||
- **SSL Setup**: `docs/deployment/ssl-setup.md`
|
||||
- **Database Migrations**: `docs/deployment/database-migration-strategy.md`
|
||||
- **Logging Configuration**: `docs/deployment/logging-configuration.md`
|
||||
@@ -1,381 +0,0 @@
|
||||
# Docker Swarm + Traefik Deployment Guide
|
||||
|
||||
Production deployment guide for the Custom PHP Framework using Docker Swarm orchestration with Traefik load balancer.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
Internet → Traefik (SSL Termination, Load Balancing)
|
||||
↓
|
||||
[Web Service - 3 Replicas]
|
||||
↓ ↓
|
||||
Database Redis Queue Workers
|
||||
(PostgreSQL) (Cache/Sessions) (2 Replicas)
|
||||
```
|
||||
|
||||
**Key Components**:
|
||||
- **Traefik v2.10**: Reverse proxy, SSL termination, automatic service discovery
|
||||
- **Web Service**: 3 replicas of PHP-FPM + Nginx (HTTP only, Traefik handles HTTPS)
|
||||
- **PostgreSQL 16**: Single instance database (manager node)
|
||||
- **Redis 7**: Sessions and cache (manager node)
|
||||
- **Queue Workers**: 2 replicas for background job processing
|
||||
- **Docker Swarm**: Native container orchestration with rolling updates and health checks
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Docker Engine 28.0+** with Swarm mode enabled
|
||||
2. **Production Server** with SSH access
|
||||
3. **SSL Certificates** in `./ssl/` directory (cert.pem, key.pem)
|
||||
4. **Environment Variables** in `.env` file on production server
|
||||
5. **Docker Image** built and available
|
||||
|
||||
## Initial Setup
|
||||
|
||||
### 1. Initialize Docker Swarm
|
||||
|
||||
On production server:
|
||||
```bash
|
||||
docker swarm init
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
docker node ls
|
||||
# Should show 1 node as Leader
|
||||
```
|
||||
|
||||
### 2. Create Docker Secrets
|
||||
|
||||
Create secrets from .env file values:
|
||||
|
||||
```bash
|
||||
cd /home/deploy/framework
|
||||
|
||||
# Create secrets (one-time setup)
|
||||
echo "$DB_PASSWORD" | docker secret create db_password -
|
||||
echo "$APP_KEY" | docker secret create app_key -
|
||||
echo "$VAULT_ENCRYPTION_KEY" | docker secret create vault_encryption_key -
|
||||
echo "$SHOPIFY_WEBHOOK_SECRET" | docker secret create shopify_webhook_secret -
|
||||
echo "$RAPIDMAIL_PASSWORD" | docker secret create rapidmail_password -
|
||||
```
|
||||
|
||||
Or use the automated script:
|
||||
```bash
|
||||
./scripts/setup-production-secrets.sh
|
||||
```
|
||||
|
||||
Verify secrets:
|
||||
```bash
|
||||
docker secret ls
|
||||
```
|
||||
|
||||
### 3. Build and Transfer Docker Image
|
||||
|
||||
On local machine:
|
||||
|
||||
**Option A: Via Private Registry** (if available):
|
||||
```bash
|
||||
# Build image
|
||||
docker build -f Dockerfile.production -t 94.16.110.151:5000/framework:latest .
|
||||
|
||||
# Push to registry
|
||||
docker push 94.16.110.151:5000/framework:latest
|
||||
```
|
||||
|
||||
**Option B: Direct Transfer via SSH** (recommended for now):
|
||||
```bash
|
||||
# Build image
|
||||
docker build -f Dockerfile.production -t 94.16.110.151:5000/framework:latest .
|
||||
|
||||
# Save and transfer to production
|
||||
docker save 94.16.110.151:5000/framework:latest | \
|
||||
ssh -i ~/.ssh/production deploy@94.16.110.151 'docker load'
|
||||
```
|
||||
|
||||
### 4. Deploy Stack
|
||||
|
||||
On production server:
|
||||
```bash
|
||||
cd /home/deploy/framework
|
||||
|
||||
# Deploy the stack
|
||||
docker stack deploy -c docker-compose.prod.yml framework
|
||||
|
||||
# Monitor deployment
|
||||
watch docker stack ps framework
|
||||
|
||||
# Check service status
|
||||
docker stack services framework
|
||||
```
|
||||
|
||||
## Health Monitoring
|
||||
|
||||
### Check Service Status
|
||||
|
||||
```bash
|
||||
# List all services
|
||||
docker stack services framework
|
||||
|
||||
# Check specific service
|
||||
docker service ps framework_web
|
||||
|
||||
# View service logs
|
||||
docker service logs framework_web -f
|
||||
docker service logs framework_traefik -f
|
||||
docker service logs framework_db -f
|
||||
```
|
||||
|
||||
### Health Check Endpoints
|
||||
|
||||
- **Main Health**: http://localhost/health (via Traefik)
|
||||
- **Traefik Dashboard**: http://traefik.localhost:8080 (manager node only)
|
||||
|
||||
### Expected Service Replicas
|
||||
|
||||
| Service | Replicas | Purpose |
|
||||
|---------|----------|---------|
|
||||
| traefik | 1 | Reverse proxy + SSL |
|
||||
| web | 3 | Application servers |
|
||||
| db | 1 | PostgreSQL database |
|
||||
| redis | 1 | Cache + sessions |
|
||||
| queue-worker | 2 | Background jobs |
|
||||
|
||||
## Rolling Updates
|
||||
|
||||
### Update Application
|
||||
|
||||
1. Build new image with updated code:
|
||||
```bash
|
||||
docker build -f Dockerfile.production -t 94.16.110.151:5000/framework:latest .
|
||||
```
|
||||
|
||||
2. Transfer to production (if no registry):
|
||||
```bash
|
||||
docker save 94.16.110.151:5000/framework:latest | \
|
||||
ssh -i ~/.ssh/production deploy@94.16.110.151 'docker load'
|
||||
```
|
||||
|
||||
3. Update the service:
|
||||
```bash
|
||||
# On production server
|
||||
docker service update --image 94.16.110.151:5000/framework:latest framework_web
|
||||
```
|
||||
|
||||
The update will:
|
||||
- Roll out to 1 container at a time (`parallelism: 1`)
|
||||
- Wait 10 seconds between updates (`delay: 10s`)
|
||||
- Start new container before stopping old one (`order: start-first`)
|
||||
- Automatically rollback on failure (`failure_action: rollback`)
|
||||
|
||||
### Monitor Update Progress
|
||||
|
||||
```bash
|
||||
# Watch update status
|
||||
watch docker service ps framework_web
|
||||
|
||||
# View update logs
|
||||
docker service logs framework_web -f --tail 50
|
||||
```
|
||||
|
||||
### Manual Rollback
|
||||
|
||||
If needed, rollback to previous version:
|
||||
```bash
|
||||
docker service rollback framework_web
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Service Won't Start
|
||||
|
||||
Check service logs:
|
||||
```bash
|
||||
docker service logs framework_web --tail 100
|
||||
```
|
||||
|
||||
Check task failures:
|
||||
```bash
|
||||
docker service ps framework_web --no-trunc
|
||||
```
|
||||
|
||||
### Container Crashing
|
||||
|
||||
Inspect individual container:
|
||||
```bash
|
||||
# Get container ID
|
||||
docker ps -a | grep framework_web
|
||||
|
||||
# View logs
|
||||
docker logs <container_id>
|
||||
|
||||
# Exec into running container
|
||||
docker exec -it <container_id> bash
|
||||
```
|
||||
|
||||
### SSL/TLS Issues
|
||||
|
||||
Traefik handles SSL termination. Check Traefik logs:
|
||||
```bash
|
||||
docker service logs framework_traefik -f
|
||||
```
|
||||
|
||||
Verify SSL certificates are mounted in docker-compose.prod.yml:
|
||||
```yaml
|
||||
volumes:
|
||||
- ./ssl:/ssl:ro
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
Check PostgreSQL health:
|
||||
```bash
|
||||
docker service logs framework_db --tail 50
|
||||
|
||||
# Exec into db container
|
||||
docker exec -it $(docker ps -q -f name=framework_db) psql -U postgres -d framework_prod
|
||||
```
|
||||
|
||||
### Redis Connection Issues
|
||||
|
||||
Check Redis availability:
|
||||
```bash
|
||||
docker service logs framework_redis --tail 50
|
||||
|
||||
# Test Redis connection
|
||||
docker exec -it $(docker ps -q -f name=framework_redis) redis-cli ping
|
||||
```
|
||||
|
||||
### Performance Issues
|
||||
|
||||
Check resource usage:
|
||||
```bash
|
||||
# Service resource limits
|
||||
docker service inspect framework_web --format='{{json .Spec.TaskTemplate.Resources}}' | jq
|
||||
|
||||
# Container stats
|
||||
docker stats
|
||||
```
|
||||
|
||||
## Scaling
|
||||
|
||||
### Scale Web Service
|
||||
|
||||
```bash
|
||||
# Scale up to 5 replicas
|
||||
docker service scale framework_web=5
|
||||
|
||||
# Scale down to 2 replicas
|
||||
docker service scale framework_web=2
|
||||
```
|
||||
|
||||
### Scale Queue Workers
|
||||
|
||||
```bash
|
||||
# Scale workers based on queue backlog
|
||||
docker service scale framework_queue-worker=4
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
|
||||
### Remove Stack
|
||||
|
||||
```bash
|
||||
# Remove entire stack
|
||||
docker stack rm framework
|
||||
|
||||
# Verify removal
|
||||
docker stack ls
|
||||
```
|
||||
|
||||
### Remove Secrets
|
||||
|
||||
```bash
|
||||
# List secrets
|
||||
docker secret ls
|
||||
|
||||
# Remove specific secret
|
||||
docker secret rm db_password
|
||||
|
||||
# Remove all framework secrets
|
||||
docker secret ls | grep -E "db_password|app_key|vault_encryption_key" | awk '{print $2}' | xargs docker secret rm
|
||||
```
|
||||
|
||||
### Leave Swarm
|
||||
|
||||
```bash
|
||||
# Force leave Swarm (removes all services and secrets)
|
||||
docker swarm leave --force
|
||||
```
|
||||
|
||||
## Network Architecture
|
||||
|
||||
### Overlay Networks
|
||||
|
||||
- **traefik-public**: External network for Traefik ↔ Web communication
|
||||
- **backend**: Internal network for Web ↔ Database/Redis communication
|
||||
|
||||
### Port Mappings
|
||||
|
||||
| Port | Service | Purpose |
|
||||
|------|---------|---------|
|
||||
| 80 | Traefik | HTTP (redirects to 443) |
|
||||
| 443 | Traefik | HTTPS (production traffic) |
|
||||
| 8080 | Traefik | Dashboard (manager node only) |
|
||||
|
||||
## Volume Management
|
||||
|
||||
### Named Volumes
|
||||
|
||||
| Volume | Purpose | Mounted In |
|
||||
|--------|---------|------------|
|
||||
| traefik-logs | Traefik access logs | traefik |
|
||||
| storage-logs | Application logs | web, queue-worker |
|
||||
| storage-uploads | User uploads | web |
|
||||
| storage-queue | Queue data | queue-worker |
|
||||
| db-data | PostgreSQL data | db |
|
||||
| redis-data | Redis persistence | redis |
|
||||
|
||||
### Backup Volumes
|
||||
|
||||
```bash
|
||||
# Backup database
|
||||
docker exec $(docker ps -q -f name=framework_db) pg_dump -U postgres framework_prod > backup.sql
|
||||
|
||||
# Backup Redis (if persistence enabled)
|
||||
docker exec $(docker ps -q -f name=framework_redis) redis-cli --rdb /data/dump.rdb
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Secrets Management**: Never commit secrets to version control, use Docker Secrets
|
||||
2. **Network Isolation**: Backend network is internal-only, no external access
|
||||
3. **SSL/TLS**: Traefik enforces HTTPS, redirects HTTP → HTTPS
|
||||
4. **Health Checks**: All services have health checks with automatic restart
|
||||
5. **Resource Limits**: Production services have memory/CPU limits
|
||||
6. **Least Privilege**: Containers run as www-data (not root) where possible
|
||||
|
||||
## Phase 2 - Monitoring (Coming Soon)
|
||||
|
||||
- Prometheus for metrics collection
|
||||
- Grafana dashboards
|
||||
- Automated PostgreSQL backups
|
||||
- Email/Slack alerting
|
||||
|
||||
## Phase 3 - CI/CD (Coming Soon)
|
||||
|
||||
- Gitea Actions workflow
|
||||
- Loki + Promtail for log aggregation
|
||||
- Performance tuning
|
||||
|
||||
## Phase 4 - High Availability (Future)
|
||||
|
||||
- Multi-node Swarm cluster
|
||||
- Varnish CDN cache layer
|
||||
- PostgreSQL Primary/Replica with pgpool
|
||||
- MinIO object storage
|
||||
|
||||
## References
|
||||
|
||||
- [Docker Swarm Documentation](https://docs.docker.com/engine/swarm/)
|
||||
- [Traefik v2 Documentation](https://doc.traefik.io/traefik/)
|
||||
- [Docker Secrets Management](https://docs.docker.com/engine/swarm/secrets/)
|
||||
297
docs/deployment/gitea-secrets-setup.md
Normal file
297
docs/deployment/gitea-secrets-setup.md
Normal file
@@ -0,0 +1,297 @@
|
||||
# Gitea Secrets Setup - Vollständige Anleitung
|
||||
|
||||
## Problem: "Secrets" fehlt in Repository Settings
|
||||
|
||||
Wenn du unter **Repository → Settings** keine "Secrets" Option siehst, kann das verschiedene Gründe haben. Diese Anleitung zeigt alle Möglichkeiten, wie Secrets in Gitea konfiguriert werden können.
|
||||
|
||||
## 📍 Wo finde ich Secrets in Gitea?
|
||||
|
||||
### Option 1: Repository Secrets (Standard)
|
||||
|
||||
**Pfad:** `Repository → Settings → Secrets`
|
||||
|
||||
⚠️ **Falls diese Option fehlt:**
|
||||
- Gitea Actions muss für das Repository aktiviert sein
|
||||
- Benötigt Berechtigung: Repository Owner oder Admin
|
||||
- Manche Gitea-Versionen haben Secrets an anderen Orten
|
||||
|
||||
### Option 2: Über Actions/Tabs
|
||||
|
||||
Manche Gitea-Versionen haben Secrets unter:
|
||||
- **Repository → Settings → Actions → Secrets**
|
||||
- **Repository → Actions → Secrets**
|
||||
|
||||
### Option 3: Organization/Admin Level
|
||||
|
||||
Falls Repository-Secrets nicht verfügbar sind, können Secrets auf Organisations-Level gesetzt werden:
|
||||
|
||||
1. **Als Admin:** `Site Administration → Actions → Secrets`
|
||||
2. **Als Org-Owner:** `Organization Settings → Actions → Secrets`
|
||||
|
||||
### Option 4: Via Gitea API (Programmatisch)
|
||||
|
||||
Falls die UI-Option fehlt, können Secrets via API gesetzt werden:
|
||||
|
||||
```bash
|
||||
# Siehe: scripts/setup-gitea-secrets.sh
|
||||
```
|
||||
|
||||
## 🔍 Diagnose: Warum sehe ich keine Secrets-Option?
|
||||
|
||||
### Checkliste:
|
||||
|
||||
1. **Ist Gitea Actions aktiviert?**
|
||||
- Gehe zu: **Site Administration → Actions → Settings**
|
||||
- Stelle sicher, dass Actions aktiviert ist
|
||||
|
||||
2. **Hast du die richtigen Berechtigungen?**
|
||||
- Du musst Repository Owner oder Admin sein
|
||||
- Prüfe: **Repository → Settings → Collaborators**
|
||||
|
||||
3. **Welche Gitea-Version wird verwendet?**
|
||||
- Neuere Versionen haben Secrets unter Repository → Settings → Secrets
|
||||
- Ältere Versionen könnten andere Pfade haben
|
||||
|
||||
4. **Sind Actions für das Repository aktiviert?**
|
||||
- Prüfe ob Workflows unter **Repository → Actions** sichtbar sind
|
||||
- Falls nicht, müssen Actions für das Repository aktiviert werden
|
||||
|
||||
## 🛠️ Lösung: Secrets manuell setzen
|
||||
|
||||
### Methode 1: Via Gitea API (Empfohlen)
|
||||
|
||||
Wenn die UI-Option fehlt, verwende das Setup-Script:
|
||||
|
||||
```bash
|
||||
# Script vorbereiten
|
||||
cd /home/michael/dev/michaelschiemer
|
||||
|
||||
# Setze deine Gitea-Credentials
|
||||
export GITEA_URL="https://git.michaelschiemer.de"
|
||||
export GITEA_TOKEN="dein-gitea-token" # Siehe unten wie man einen Token erstellt
|
||||
export REPO_OWNER="dein-username" # Oder Organization-Name
|
||||
export REPO_NAME="michaelschiemer"
|
||||
|
||||
# Setze die Secrets
|
||||
./scripts/setup-gitea-secrets.sh
|
||||
```
|
||||
|
||||
**Gitea Token erstellen:**
|
||||
1. Gehe zu: `https://git.michaelschiemer.de/user/settings/applications`
|
||||
2. Scrolle zu "Generate New Token"
|
||||
3. Name: z.B. "CI/CD Secrets Setup"
|
||||
4. Scopes: `write:repository` (mindestens)
|
||||
5. Klicke "Generate Token"
|
||||
6. Kopiere den Token (wird nur einmal angezeigt!)
|
||||
|
||||
### Methode 2: Environment-Variablen im Runner (Alternative)
|
||||
|
||||
Falls Repository Secrets wirklich nicht verfügbar sind, können Secrets auch als Environment-Variablen im Runner konfiguriert werden:
|
||||
|
||||
**In `deployment/gitea-runner/docker-compose.yml`:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
gitea-runner:
|
||||
environment:
|
||||
- REGISTRY_USER=admin
|
||||
- REGISTRY_PASSWORD=registry-secure-password-2025
|
||||
# Weitere Secrets...
|
||||
```
|
||||
|
||||
⚠️ **Nicht empfohlen:** Weniger sicher, da Secrets im docker-compose.yml gespeichert werden.
|
||||
|
||||
### Methode 3: Secrets im Workflow hardcoden (NICHT EMPFOHLEN!)
|
||||
|
||||
**⚠️ NIEMALS PASSWÖRTER IM CODE SPEICHERN!**
|
||||
|
||||
Diese Methode sollte nur für Tests verwendet werden und ist für Produktion unsicher.
|
||||
|
||||
## 📝 Schritt-für-Schritt: Secrets via API setzen
|
||||
|
||||
### Schritt 1: Gitea Token erstellen
|
||||
|
||||
1. Gehe zu: `https://git.michaelschiemer.de/user/settings/applications`
|
||||
2. Scrolle zu "Generate New Token"
|
||||
3. **Name:** `CI/CD Secrets Management`
|
||||
4. **Scopes:** Wähle:
|
||||
- ✅ `read:repository`
|
||||
- ✅ `write:repository`
|
||||
- ✅ `read:organization` (falls Org-Repo)
|
||||
5. Klicke **"Generate Token"**
|
||||
6. **Kopiere den Token sofort** (wird nur einmal angezeigt!)
|
||||
|
||||
### Schritt 2: Repository-Informationen finden
|
||||
|
||||
**Repository Owner:**
|
||||
- Gehe zu deinem Repository: `https://git.michaelschiemer.de/[username]/michaelschiemer`
|
||||
- Der erste Teil nach `/` ist der Owner (Username oder Org-Name)
|
||||
|
||||
**Repository Name:**
|
||||
- Der zweite Teil ist der Repository-Name (meist `michaelschiemer`)
|
||||
|
||||
### Schritt 3: Setup-Script ausführen
|
||||
|
||||
```bash
|
||||
cd /home/michael/dev/michaelschiemer
|
||||
|
||||
# Konfiguriere die Variablen
|
||||
export GITEA_URL="https://git.michaelschiemer.de"
|
||||
export GITEA_TOKEN="dein-token-hier"
|
||||
export REPO_OWNER="dein-username"
|
||||
export REPO_NAME="michaelschiemer"
|
||||
export REGISTRY_PASSWORD="registry-secure-password-2025"
|
||||
|
||||
# Führe das Script aus
|
||||
bash scripts/setup-gitea-secrets.sh
|
||||
```
|
||||
|
||||
Das Script setzt automatisch:
|
||||
- `REGISTRY_USER` = `admin`
|
||||
- `REGISTRY_PASSWORD` = Wert von `$REGISTRY_PASSWORD`
|
||||
- `SSH_PRIVATE_KEY` = aus `~/.ssh/production`
|
||||
|
||||
### Schritt 4: Verifizierung
|
||||
|
||||
Nach dem Ausführen des Scripts:
|
||||
|
||||
1. **Prüfe ob Secrets gesetzt wurden:**
|
||||
```bash
|
||||
# Teste mit einem Workflow
|
||||
# Gehe zu: Repository → Actions → Test Registry Credentials → Run workflow
|
||||
```
|
||||
|
||||
2. **Oder prüfe via API:**
|
||||
```bash
|
||||
curl -H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/actions/secrets"
|
||||
```
|
||||
|
||||
## 🔐 Alternative: Secrets in Runner Environment
|
||||
|
||||
Falls Repository Secrets gar nicht funktionieren, können Secrets auch als Environment-Variablen im Runner konfiguriert werden:
|
||||
|
||||
### Schritt 1: .env Datei erstellen
|
||||
|
||||
```bash
|
||||
cd deployment/gitea-runner
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### Schritt 2: Secrets zur .env hinzufügen
|
||||
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
Füge hinzu:
|
||||
```bash
|
||||
REGISTRY_USER=admin
|
||||
REGISTRY_PASSWORD=registry-secure-password-2025
|
||||
# SSH_PRIVATE_KEY würde hier nicht gesetzt werden (zu lang)
|
||||
```
|
||||
|
||||
### Schritt 3: docker-compose.yml anpassen
|
||||
|
||||
```yaml
|
||||
services:
|
||||
gitea-runner:
|
||||
environment:
|
||||
- REGISTRY_USER=${REGISTRY_USER:-admin}
|
||||
- REGISTRY_PASSWORD=${REGISTRY_PASSWORD}
|
||||
# ... rest of config
|
||||
```
|
||||
|
||||
### Schritt 4: Workflow anpassen
|
||||
|
||||
Im Workflow müssen Secrets dann anders geladen werden:
|
||||
|
||||
```yaml
|
||||
- name: Login to Registry
|
||||
env:
|
||||
REGISTRY_USER: ${REGISTRY_USER}
|
||||
REGISTRY_PASSWORD: ${REGISTRY_PASSWORD}
|
||||
run: |
|
||||
# Secrets werden jetzt aus Runner Environment geladen
|
||||
```
|
||||
|
||||
⚠️ **Nachteil:** Secrets sind dann im Runner-Environment und nicht repository-spezifisch.
|
||||
|
||||
## 🧪 Test ob Secrets funktionieren
|
||||
|
||||
### Test 1: Workflow ausführen
|
||||
|
||||
```bash
|
||||
# Gehe zu: Repository → Actions → Test Registry Credentials → Run workflow
|
||||
```
|
||||
|
||||
### Test 2: Debug-Output im Workflow
|
||||
|
||||
Füge temporär Debug-Output hinzu:
|
||||
|
||||
```yaml
|
||||
- name: Debug Secrets
|
||||
run: |
|
||||
echo "REGISTRY_USER length: ${#REGISTRY_USER}"
|
||||
echo "REGISTRY_PASSWORD length: ${#REGISTRY_PASSWORD}"
|
||||
# Zeigt die Länge, nicht den Inhalt (für Sicherheit)
|
||||
```
|
||||
|
||||
Wenn beide > 0 sind, funktionieren die Secrets.
|
||||
|
||||
### Test 3: Lokales Test-Script
|
||||
|
||||
```bash
|
||||
export REGISTRY_USER="admin"
|
||||
export REGISTRY_PASSWORD="registry-secure-password-2025"
|
||||
./scripts/test-registry-credentials.sh
|
||||
```
|
||||
|
||||
## 📚 Nützliche Links
|
||||
|
||||
- **Gitea Actions Docs:** https://docs.gitea.io/en-us/actions/
|
||||
- **Secrets API:** https://docs.gitea.io/en-us/api-usage/#repository-secrets
|
||||
- **Setup Script:** `scripts/setup-gitea-secrets.sh`
|
||||
|
||||
## ❓ Häufige Fragen
|
||||
|
||||
### Q: Warum sehe ich keine "Secrets" Option?
|
||||
|
||||
**A:** Mögliche Gründe:
|
||||
1. Gitea Actions ist nicht aktiviert
|
||||
2. Du hast nicht die nötigen Berechtigungen (Repository Owner/Admin)
|
||||
3. Deine Gitea-Version hat Secrets an einem anderen Ort
|
||||
4. Secrets müssen via API gesetzt werden
|
||||
|
||||
### Q: Kann ich Secrets für mehrere Repositories setzen?
|
||||
|
||||
**A:** Ja, über:
|
||||
- **Organization Secrets:** Für alle Repos in der Organisation
|
||||
- **API:** Script mehrmals ausführen mit verschiedenen `REPO_NAME`
|
||||
|
||||
### Q: Sind Secrets verschlüsselt?
|
||||
|
||||
**A:** Ja, Gitea verschlüsselt Secrets vor der Speicherung.
|
||||
|
||||
### Q: Wie ändere ich ein Secret?
|
||||
|
||||
**A:**
|
||||
- Via UI: Bearbeiten (falls verfügbar)
|
||||
- Via API: Script erneut ausführen (überschreibt das Secret)
|
||||
- Via Script: `setup-gitea-secrets.sh` erneut ausführen
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
**Schnellste Methode (wenn API verfügbar):**
|
||||
|
||||
```bash
|
||||
export GITEA_URL="https://git.michaelschiemer.de"
|
||||
export GITEA_TOKEN="dein-token"
|
||||
export REPO_OWNER="dein-username"
|
||||
export REPO_NAME="michaelschiemer"
|
||||
export REGISTRY_PASSWORD="registry-secure-password-2025"
|
||||
|
||||
bash scripts/setup-gitea-secrets.sh
|
||||
```
|
||||
|
||||
Das war's! Secrets sollten jetzt funktionieren.
|
||||
@@ -1,800 +0,0 @@
|
||||
# Production Deployment Guide
|
||||
|
||||
Umfassende Anleitung für das Deployment der Custom PHP Framework Anwendung auf dem Production Server.
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
1. [Architektur-Übersicht](#architektur-übersicht)
|
||||
2. [Voraussetzungen](#voraussetzungen)
|
||||
3. [Sicherheits-Setup](#sicherheits-setup)
|
||||
4. [Docker Registry Setup](#docker-registry-setup)
|
||||
5. [Production Image Build](#production-image-build)
|
||||
6. [Deployment Prozess](#deployment-prozess)
|
||||
7. [Troubleshooting](#troubleshooting)
|
||||
8. [Monitoring](#monitoring)
|
||||
|
||||
---
|
||||
|
||||
## Architektur-Übersicht
|
||||
|
||||
### Development vs Production
|
||||
|
||||
**Development** (docker-compose.yml):
|
||||
- Separate Container: Nginx + PHP-FPM
|
||||
- Source Code via Volume Mounts
|
||||
- Hot-Reload für Development
|
||||
- Xdebug aktiviert
|
||||
|
||||
**Production** (docker-compose.prod.yml):
|
||||
- Single Container: Supervisor → Nginx + PHP-FPM
|
||||
- Code im Image eingebacken
|
||||
- Minimale Volume Mounts (nur logs/uploads)
|
||||
- Optimiert für Performance
|
||||
|
||||
### Production Stack
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Production Server (94.16.110.151) │
|
||||
│ │
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐│
|
||||
│ │ Web │ │ PHP │ │ Redis ││
|
||||
│ │ (Supervisor│ │ │ │ Cache ││
|
||||
│ │ Nginx + │ │ │ │ ││
|
||||
│ │ PHP-FPM) │ │ │ │ ││
|
||||
│ └────────────┘ └────────────┘ └────────────┘│
|
||||
│ │
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐│
|
||||
│ │ PostgreSQL │ │ Queue │ │ Watchtower ││
|
||||
│ │ Database │ │ Worker │ │ Auto-Update││
|
||||
│ └────────────┘ └────────────┘ └────────────┘│
|
||||
│ │
|
||||
│ Monitoring (VPN-only): │
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐│
|
||||
│ │ Prometheus │ │ Grafana │ │ Portainer ││
|
||||
│ │ :9090 │ │ :3000 │ │ :9443 ││
|
||||
│ └────────────┘ └────────────┘ └────────────┘│
|
||||
└─────────────────────────────────────────────────┘
|
||||
▲
|
||||
│ WireGuard VPN (10.8.0.0/24)
|
||||
│
|
||||
┌───┴────┐
|
||||
│ Client │
|
||||
└────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
### Server Requirements
|
||||
|
||||
- **OS**: Ubuntu 22.04 LTS (oder neuer)
|
||||
- **RAM**: Minimum 4GB (empfohlen: 8GB+)
|
||||
- **CPU**: 2+ Cores
|
||||
- **Disk**: 50GB+ freier Speicherplatz
|
||||
- **Network**: Statische IP oder DNS
|
||||
|
||||
### Installierte Software
|
||||
|
||||
```bash
|
||||
# Docker & Docker Compose
|
||||
docker --version # 24.0+
|
||||
docker-compose --version # 2.20+
|
||||
|
||||
# WireGuard (für sicheren Zugriff)
|
||||
wg --version
|
||||
|
||||
# SSL Tools
|
||||
openssl version
|
||||
```
|
||||
|
||||
### Ports
|
||||
|
||||
**Public (Firewall offen)**:
|
||||
- `8888`: HTTP (optional, für HTTP→HTTPS Redirect)
|
||||
- `8443`: HTTPS (Hauptzugang)
|
||||
- `51820`: WireGuard VPN (UDP)
|
||||
|
||||
**VPN-only (über 10.8.0.1)**:
|
||||
- `9090`: Prometheus
|
||||
- `3000`: Grafana
|
||||
- `9443`: Portainer
|
||||
|
||||
**Internal (nicht extern erreichbar)**:
|
||||
- `5432`: PostgreSQL
|
||||
- `6379`: Redis
|
||||
- `9000`: PHP-FPM
|
||||
|
||||
---
|
||||
|
||||
## Sicherheits-Setup
|
||||
|
||||
### 1. WireGuard VPN
|
||||
|
||||
WireGuard bietet verschlüsselten Zugang zum Production Server für Administration und Monitoring.
|
||||
|
||||
**Server Installation**:
|
||||
```bash
|
||||
# Als root auf Production Server
|
||||
apt update
|
||||
apt install -y wireguard
|
||||
|
||||
# Schlüssel generieren
|
||||
cd /etc/wireguard
|
||||
umask 077
|
||||
wg genkey | tee server_private.key | wg pubkey > server_public.key
|
||||
|
||||
# Server Config
|
||||
cat > /etc/wireguard/wg0.conf <<'EOF'
|
||||
[Interface]
|
||||
Address = 10.8.0.1/24
|
||||
ListenPort = 51820
|
||||
PrivateKey = <server_private_key>
|
||||
|
||||
# Client (Development Machine)
|
||||
[Peer]
|
||||
PublicKey = <client_public_key>
|
||||
AllowedIPs = 10.8.0.2/32
|
||||
EOF
|
||||
|
||||
# Service starten
|
||||
systemctl enable wg-quick@wg0
|
||||
systemctl start wg-quick@wg0
|
||||
systemctl status wg-quick@wg0
|
||||
```
|
||||
|
||||
**Client Configuration** (`/etc/wireguard/wg0-production.conf`):
|
||||
```ini
|
||||
[Interface]
|
||||
Address = 10.8.0.2/32
|
||||
PrivateKey = <client_private_key>
|
||||
DNS = 1.1.1.1
|
||||
|
||||
[Peer]
|
||||
PublicKey = <server_public_key>
|
||||
Endpoint = 94.16.110.151:51820
|
||||
AllowedIPs = 10.8.0.0/24, 94.16.110.151/32
|
||||
PersistentKeepalive = 25
|
||||
```
|
||||
|
||||
**Client Start**:
|
||||
```bash
|
||||
sudo wg-quick up wg0-production
|
||||
sudo wg show # Verify connection
|
||||
ping 10.8.0.1 # Test connectivity
|
||||
```
|
||||
|
||||
### 2. Firewall Configuration
|
||||
|
||||
**UFW Rules** (auf Production Server):
|
||||
```bash
|
||||
# Default policies
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
|
||||
# SSH (nur von spezifischen IPs)
|
||||
ufw allow from <deine_ip> to any port 22
|
||||
|
||||
# WireGuard
|
||||
ufw allow 51820/udp
|
||||
|
||||
# HTTP/HTTPS
|
||||
ufw allow 8888/tcp # HTTP (optional)
|
||||
ufw allow 8443/tcp # HTTPS
|
||||
|
||||
# Enable firewall
|
||||
ufw enable
|
||||
ufw status verbose
|
||||
```
|
||||
|
||||
### 3. SSL/TLS Zertifikate
|
||||
|
||||
**Development/Testing** (Self-Signed):
|
||||
```bash
|
||||
# Bereits vorhanden in ./ssl/
|
||||
# - cert.pem
|
||||
# - key.pem
|
||||
```
|
||||
|
||||
**Production** (Let's Encrypt empfohlen):
|
||||
```bash
|
||||
# Mit certbot
|
||||
certbot certonly --standalone -d yourdomain.com
|
||||
# Zertifikate nach ./ssl/ kopieren
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker Registry Setup
|
||||
|
||||
### Local Registry on Production Server
|
||||
|
||||
Für sichere, private Image-Verwaltung läuft eine lokale Docker Registry auf dem Production Server.
|
||||
|
||||
**Registry starten**:
|
||||
```bash
|
||||
docker run -d \
|
||||
--restart=always \
|
||||
--name registry \
|
||||
-p 127.0.0.1:5000:5000 \
|
||||
registry:2
|
||||
```
|
||||
|
||||
**Verify**:
|
||||
```bash
|
||||
curl http://localhost:5000/v2/_catalog
|
||||
```
|
||||
|
||||
**Registry in Docker konfigurieren**:
|
||||
|
||||
`/etc/docker/daemon.json`:
|
||||
```json
|
||||
{
|
||||
"insecure-registries": ["94.16.110.151:5000"]
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Production Image Build
|
||||
|
||||
### Build-Prozess
|
||||
|
||||
Das Production Image wird lokal gebaut und dann zur Registry gepusht.
|
||||
|
||||
**1. Production Dockerfile** (`Dockerfile.production`):
|
||||
|
||||
```dockerfile
|
||||
# Multi-stage build für optimale Image-Größe
|
||||
FROM php:8.3-fpm-alpine AS base
|
||||
|
||||
# System dependencies
|
||||
RUN apk add --no-cache \
|
||||
nginx \
|
||||
supervisor \
|
||||
postgresql-dev \
|
||||
libpq \
|
||||
&& docker-php-ext-install pdo pdo_pgsql
|
||||
|
||||
# PHP Configuration
|
||||
COPY docker/php/php.production.ini /usr/local/etc/php/conf.d/production.ini
|
||||
COPY docker/php/opcache.ini /usr/local/etc/php/conf.d/opcache.ini
|
||||
COPY docker/php/zz-docker.production.conf /usr/local/etc/php-fpm.d/zz-docker.conf
|
||||
|
||||
# Nginx Configuration
|
||||
COPY docker/nginx/nginx.production.conf /etc/nginx/nginx.conf
|
||||
COPY docker/nginx/default.production.conf /etc/nginx/http.d/default.conf
|
||||
|
||||
# Supervisor Configuration
|
||||
COPY docker/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# Application Code
|
||||
WORKDIR /var/www/html
|
||||
COPY --chown=www-data:www-data . .
|
||||
|
||||
# Composer dependencies (Production only)
|
||||
RUN composer install --no-dev --optimize-autoloader --no-interaction
|
||||
|
||||
# NPM build
|
||||
RUN npm ci && npm run build
|
||||
|
||||
# Permissions
|
||||
RUN chown -R www-data:www-data /var/www/html/storage \
|
||||
&& chmod -R 775 /var/www/html/storage
|
||||
|
||||
# Start Supervisor (manages nginx + php-fpm)
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
```
|
||||
|
||||
**2. Build Command**:
|
||||
|
||||
```bash
|
||||
# Im Projekt-Root
|
||||
docker build \
|
||||
-f Dockerfile.production \
|
||||
-t 94.16.110.151:5000/framework:latest \
|
||||
.
|
||||
```
|
||||
|
||||
**3. Push to Registry**:
|
||||
|
||||
```bash
|
||||
docker push 94.16.110.151:5000/framework:latest
|
||||
```
|
||||
|
||||
**4. Verify Push**:
|
||||
|
||||
```bash
|
||||
curl http://94.16.110.151:5000/v2/framework/tags/list
|
||||
```
|
||||
|
||||
### Wichtige Konfigurationsdateien
|
||||
|
||||
#### Supervisor Configuration (`docker/supervisor/supervisord.conf`)
|
||||
|
||||
```ini
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
silent=false
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/var/run/supervisord.pid
|
||||
loglevel=info
|
||||
|
||||
[program:php-fpm]
|
||||
command=php-fpm -F
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=true
|
||||
startretries=3
|
||||
|
||||
[program:nginx]
|
||||
command=nginx -g 'daemon off;'
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
autorestart=true
|
||||
startretries=3
|
||||
depends_on=php-fpm
|
||||
```
|
||||
|
||||
**Wichtige Änderungen**:
|
||||
- `silent=false` + `logfile=/dev/null`: Supervisor loggt nach stdout/stderr statt Datei
|
||||
- Grund: Python's logging kann `/dev/stdout` oder `/proc/self/fd/1` nicht im append-mode öffnen
|
||||
|
||||
#### PHP-FPM Production Config (`docker/php/zz-docker.production.conf`)
|
||||
|
||||
```ini
|
||||
[www]
|
||||
user = www-data
|
||||
group = www-data
|
||||
listen = 9000
|
||||
listen.owner = www-data
|
||||
listen.group = www-data
|
||||
pm = dynamic
|
||||
pm.max_children = 50
|
||||
pm.start_servers = 10
|
||||
pm.min_spare_servers = 5
|
||||
pm.max_spare_servers = 20
|
||||
pm.max_requests = 500
|
||||
```
|
||||
|
||||
**Wichtig**: User/Group explizit auf `www-data` setzen, da Container als root läuft.
|
||||
|
||||
---
|
||||
|
||||
## Deployment Prozess
|
||||
|
||||
### Docker Compose Setup
|
||||
|
||||
**Base Configuration** (`docker-compose.yml`):
|
||||
- Definiert alle Services für Development
|
||||
- Wird **nicht** auf Production Server deployed
|
||||
|
||||
**Production Overrides** (`docker-compose.prod.yml`):
|
||||
- Merged mit base config
|
||||
- Production-spezifische Einstellungen
|
||||
|
||||
### Production Override Highlights
|
||||
|
||||
**Web Service**:
|
||||
```yaml
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
pull_policy: always # Immer von Registry pullen, nie bauen
|
||||
entrypoint: [] # Entrypoint von Base-Image clearen
|
||||
command: ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
user: root # Container läuft als root, PHP-FPM workers als www-data
|
||||
volumes:
|
||||
- ./storage/logs:/var/www/html/storage/logs:rw
|
||||
- ./storage/uploads:/var/www/html/storage/uploads:rw
|
||||
- ./ssl:/var/www/ssl:ro
|
||||
environment:
|
||||
- APP_ENV=production
|
||||
labels:
|
||||
com.centurylinklabs.watchtower.enable: "true"
|
||||
```
|
||||
|
||||
**Wichtige Overrides**:
|
||||
1. `pull_policy: always`: Verhindert lokales Build, zwingt Registry-Pull
|
||||
2. `entrypoint: []`: Clearen des inherited entrypoint vom Base PHP-Image
|
||||
3. `command: [...]`: Expliziter Start-Command für Supervisor
|
||||
4. `user: root`: Nötig für Supervisor, PHP-FPM läuft intern als www-data
|
||||
|
||||
### Deployment Steps
|
||||
|
||||
**1. Files auf Server kopieren**:
|
||||
|
||||
```bash
|
||||
# Lokale Entwicklungsmaschine (via WireGuard)
|
||||
scp docker-compose.prod.yml deploy@94.16.110.151:/home/deploy/framework/
|
||||
scp .env.production deploy@94.16.110.151:/home/deploy/framework/.env
|
||||
```
|
||||
|
||||
**2. Auf Server: Pull und Deploy**:
|
||||
|
||||
```bash
|
||||
# SSH auf Production Server
|
||||
ssh deploy@94.16.110.151
|
||||
|
||||
# In Projekt-Verzeichnis
|
||||
cd /home/deploy/framework
|
||||
|
||||
# Pull latest image
|
||||
docker pull 94.16.110.151:5000/framework:latest
|
||||
|
||||
# Deploy Stack
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||
|
||||
# Check Status
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml ps
|
||||
```
|
||||
|
||||
**3. Logs überwachen**:
|
||||
|
||||
```bash
|
||||
# Alle Container
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml logs -f
|
||||
|
||||
# Spezifischer Container
|
||||
docker logs -f web
|
||||
docker logs -f php
|
||||
```
|
||||
|
||||
### Deployment Verification
|
||||
|
||||
**Container Health Checks**:
|
||||
```bash
|
||||
# Alle Container sollten "healthy" sein
|
||||
docker-compose ps
|
||||
|
||||
# Output sollte zeigen:
|
||||
# web Up (healthy)
|
||||
# php Up (healthy)
|
||||
# db Up (healthy)
|
||||
# redis Up (healthy)
|
||||
```
|
||||
|
||||
**Supervisor Status (im web container)**:
|
||||
```bash
|
||||
docker exec web supervisorctl status
|
||||
|
||||
# Output:
|
||||
# nginx RUNNING pid 7, uptime 0:05:23
|
||||
# php-fpm RUNNING pid 8, uptime 0:05:23
|
||||
```
|
||||
|
||||
**Nginx & PHP-FPM Processes**:
|
||||
```bash
|
||||
docker exec web ps aux | grep -E 'nginx|php-fpm'
|
||||
|
||||
# Sollte zeigen:
|
||||
# root 1 supervisor
|
||||
# root 7 nginx: master
|
||||
# www-data nginx: worker (mehrere)
|
||||
# root 8 php-fpm: master
|
||||
# www-data php-fpm: pool www (mehrere)
|
||||
```
|
||||
|
||||
**Application Test**:
|
||||
```bash
|
||||
# Von lokalem Rechner (via WireGuard)
|
||||
curl -k -I https://94.16.110.151:8443/
|
||||
|
||||
# Erwartete Response:
|
||||
# HTTP/2 200
|
||||
# server: nginx
|
||||
# content-type: text/html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problem 1: Supervisor Log File Permission Denied
|
||||
|
||||
**Symptom**:
|
||||
```
|
||||
PermissionError: [Errno 13] Permission denied: '/var/log/supervisor/supervisord.log'
|
||||
```
|
||||
|
||||
**Ursache**: Supervisor kann nicht in `/var/log/supervisor/` schreiben, selbst als root.
|
||||
|
||||
**Lösung**: `supervisord.conf` ändern:
|
||||
```ini
|
||||
silent=false
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
```
|
||||
|
||||
**Grund**: Python's logging library kann `/dev/stdout` oder `/proc/self/fd/1` nicht im append-mode öffnen. `/dev/null` + `silent=false` macht Supervisor's logging auf stdout/stderr.
|
||||
|
||||
### Problem 2: EACCES Errors in Web Container
|
||||
|
||||
**Symptom**:
|
||||
```
|
||||
CRIT could not write pidfile /var/run/supervisord.pid
|
||||
spawnerr: unknown error making dispatchers for 'nginx': EACCES
|
||||
```
|
||||
|
||||
**Ursache**: Web container läuft nicht als root, sondern mit inherited user von base config.
|
||||
|
||||
**Lösung**: `docker-compose.prod.yml` - `user: root` setzen:
|
||||
```yaml
|
||||
web:
|
||||
user: root
|
||||
```
|
||||
|
||||
### Problem 3: Docker Entrypoint Override funktioniert nicht
|
||||
|
||||
**Symptom**: Container command zeigt entrypoint prepended:
|
||||
```
|
||||
/usr/local/bin/docker-entrypoint.sh /usr/bin/supervisord -c ...
|
||||
```
|
||||
|
||||
**Ursache**: Base `docker-compose.yml` hat `web` service mit separate build context. Inherited ENTRYPOINT vom Base PHP-Image wird prepended.
|
||||
|
||||
**Lösung**: Explizit entrypoint clearen:
|
||||
```yaml
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
pull_policy: always
|
||||
entrypoint: [] # WICHTIG: Entrypoint clearen
|
||||
command: ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
```
|
||||
|
||||
### Problem 4: Queue Worker restarts kontinuierlich
|
||||
|
||||
**Symptom**:
|
||||
```
|
||||
docker ps # zeigt queue-worker als "Restarting"
|
||||
```
|
||||
|
||||
**Ursache**: Base `docker-compose.yml` command sucht `/var/www/html/worker.php` das nicht existiert.
|
||||
|
||||
**Temporary Fix**: Service deaktivieren in `docker-compose.prod.yml`:
|
||||
```yaml
|
||||
queue-worker:
|
||||
deploy:
|
||||
replicas: 0
|
||||
```
|
||||
|
||||
**Proper Fix**: Richtigen Worker-Command konfigurieren:
|
||||
```yaml
|
||||
queue-worker:
|
||||
command: ["php", "/var/www/html/console.php", "queue:work"]
|
||||
```
|
||||
|
||||
### Problem 5: HTTP Port 80 nicht erreichbar
|
||||
|
||||
**Symptom**: `curl http://94.16.110.151:8888/` → Connection refused
|
||||
|
||||
**Mögliche Ursachen**:
|
||||
1. Nginx nicht auf Port 80 listening (nur 443)
|
||||
2. Firewall blockiert Port 8888
|
||||
3. Intentional (HTTPS-only Configuration)
|
||||
|
||||
**Debug**:
|
||||
```bash
|
||||
# Im Container checken
|
||||
docker exec web netstat -tlnp | grep :80
|
||||
|
||||
# Nginx config testen
|
||||
docker exec web nginx -t
|
||||
|
||||
# Nginx config anschauen
|
||||
docker exec web cat /etc/nginx/http.d/default.conf
|
||||
```
|
||||
|
||||
**Fix (falls HTTP→HTTPS Redirect gewünscht)**:
|
||||
In `docker/nginx/default.production.conf`:
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Prometheus
|
||||
|
||||
**Zugang**: http://10.8.0.1:9090 (nur via WireGuard)
|
||||
|
||||
**Konfiguration**: `monitoring/prometheus/prometheus.yml`
|
||||
|
||||
**Scraped Targets**:
|
||||
- Framework Application Metrics
|
||||
- Container Metrics (cAdvisor)
|
||||
- Node Exporter (Server Metrics)
|
||||
|
||||
### Grafana
|
||||
|
||||
**Zugang**: http://10.8.0.1:3000 (nur via WireGuard)
|
||||
|
||||
**Default Login**:
|
||||
- User: `admin`
|
||||
- Password: `${GRAFANA_PASSWORD}` (aus `.env`)
|
||||
|
||||
**Dashboards**: `monitoring/grafana/provisioning/dashboards/`
|
||||
|
||||
### Portainer
|
||||
|
||||
**Zugang**: https://10.8.0.1:9443 (nur via WireGuard)
|
||||
|
||||
**Features**:
|
||||
- Container Management
|
||||
- Stack Deployment
|
||||
- Log Viewing
|
||||
- Resource Usage
|
||||
|
||||
### Watchtower Auto-Update
|
||||
|
||||
Watchtower überwacht Container mit Label `com.centurylinklabs.watchtower.enable: "true"` und updated sie automatisch bei neuen Images.
|
||||
|
||||
**Konfiguration**:
|
||||
```yaml
|
||||
watchtower:
|
||||
environment:
|
||||
WATCHTOWER_CLEANUP: "true"
|
||||
WATCHTOWER_POLL_INTERVAL: 300 # 5 Minuten
|
||||
WATCHTOWER_LABEL_ENABLE: "true"
|
||||
WATCHTOWER_NOTIFICATIONS: "shoutrrr"
|
||||
WATCHTOWER_NOTIFICATION_URL: "${WATCHTOWER_NOTIFICATION_URL}"
|
||||
```
|
||||
|
||||
**Monitoren**:
|
||||
```bash
|
||||
docker logs -f watchtower
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Image Updates
|
||||
|
||||
**1. Lokal neues Image bauen**:
|
||||
```bash
|
||||
docker build -f Dockerfile.production -t 94.16.110.151:5000/framework:latest .
|
||||
docker push 94.16.110.151:5000/framework:latest
|
||||
```
|
||||
|
||||
**2. Auf Server**:
|
||||
```bash
|
||||
# Watchtower erkennt Update automatisch innerhalb von 5 Minuten
|
||||
# Oder manuell:
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
### Database Backups
|
||||
|
||||
```bash
|
||||
# Manual Backup
|
||||
docker exec db pg_dump -U framework_user framework_db > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
|
||||
# Automated (via cron)
|
||||
0 2 * * * /home/deploy/scripts/backup-database.sh
|
||||
```
|
||||
|
||||
### Log Rotation
|
||||
|
||||
Logs in `./storage/logs/` automatisch rotieren:
|
||||
|
||||
```bash
|
||||
# /etc/logrotate.d/framework
|
||||
/home/deploy/framework/storage/logs/*.log {
|
||||
daily
|
||||
rotate 14
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
missingok
|
||||
create 0640 www-data www-data
|
||||
}
|
||||
```
|
||||
|
||||
### SSL Certificate Renewal
|
||||
|
||||
**Let's Encrypt** (automatisch via certbot):
|
||||
```bash
|
||||
certbot renew --deploy-hook "docker exec web nginx -s reload"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] WireGuard VPN konfiguriert und aktiv
|
||||
- [ ] Firewall (UFW) konfiguriert und enabled
|
||||
- [ ] Nur benötigte Ports offen (8443, 51820)
|
||||
- [ ] Monitoring nur via VPN erreichbar (10.8.0.1:*)
|
||||
- [ ] SSL/TLS Zertifikate gültig
|
||||
- [ ] `.env` Secrets nicht in Git committed
|
||||
- [ ] Database Credentials rotiert
|
||||
- [ ] Redis Password gesetzt
|
||||
- [ ] Docker Registry läuft lokal (nicht public)
|
||||
- [ ] Container laufen mit minimal privileges
|
||||
- [ ] Watchtower auto-updates aktiviert
|
||||
- [ ] Backup-Strategie implementiert
|
||||
- [ ] Log monitoring aktiv
|
||||
|
||||
---
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
### PHP-FPM
|
||||
|
||||
`docker/php/zz-docker.production.conf`:
|
||||
```ini
|
||||
pm.max_children = 50 # Max. gleichzeitige Requests
|
||||
pm.start_servers = 10 # Initial workers
|
||||
pm.min_spare_servers = 5 # Min. idle workers
|
||||
pm.max_spare_servers = 20 # Max. idle workers
|
||||
pm.max_requests = 500 # Worker recycling
|
||||
```
|
||||
|
||||
**Tuning basierend auf RAM**:
|
||||
- 4GB RAM: max_children = 30
|
||||
- 8GB RAM: max_children = 50
|
||||
- 16GB RAM: max_children = 100
|
||||
|
||||
### OPcache
|
||||
|
||||
`docker/php/opcache.ini`:
|
||||
```ini
|
||||
opcache.enable=1
|
||||
opcache.memory_consumption=128
|
||||
opcache.interned_strings_buffer=8
|
||||
opcache.max_accelerated_files=10000
|
||||
opcache.validate_timestamps=0 # Production: keine Timestamp-Checks
|
||||
opcache.revalidate_freq=0
|
||||
```
|
||||
|
||||
### Nginx
|
||||
|
||||
```nginx
|
||||
worker_processes auto;
|
||||
worker_connections 1024;
|
||||
keepalive_timeout 65;
|
||||
client_max_body_size 20M;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contact & Support
|
||||
|
||||
**Production Server**: 94.16.110.151
|
||||
**VPN Gateway**: 10.8.0.1
|
||||
**Documentation**: `/home/deploy/framework/docs/`
|
||||
**Issue Tracker**: [GitHub/GitLab URL]
|
||||
|
||||
---
|
||||
|
||||
## Change Log
|
||||
|
||||
### 2025-10-28 - Initial Production Deployment
|
||||
|
||||
**Changes**:
|
||||
- Supervisor logging: `/dev/null` + `silent=false`
|
||||
- docker-compose.prod.yml: `user: root` für web, php, queue-worker
|
||||
- docker-compose.prod.yml: `entrypoint: []` für web service
|
||||
- docker-compose.prod.yml: `pull_policy: always` für registry images
|
||||
|
||||
**Deployed**:
|
||||
- Image: `94.16.110.151:5000/framework:latest`
|
||||
- Digest: `sha256:eee1db20b9293cf611f53d01de68e94df1cfb3c748fe967849e080d19b9e4c8b`
|
||||
|
||||
**Status**: ✅ Deployment erfolgreich, Container healthy
|
||||
@@ -1,227 +0,0 @@
|
||||
# Quick Deploy Guide
|
||||
|
||||
Schnellanleitung für Production Deployments.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- WireGuard VPN aktiv: `sudo wg-quick up wg0-production`
|
||||
- SSH-Zugang konfiguriert
|
||||
- Docker Registry läuft auf Production Server
|
||||
|
||||
## Deployment in 5 Schritten
|
||||
|
||||
### 1. Image bauen und pushen
|
||||
|
||||
```bash
|
||||
# Im Projekt-Root
|
||||
docker build -f Dockerfile.production -t 94.16.110.151:5000/framework:latest .
|
||||
docker push 94.16.110.151:5000/framework:latest
|
||||
```
|
||||
|
||||
**Verify Push**:
|
||||
```bash
|
||||
curl http://94.16.110.151:5000/v2/framework/tags/list
|
||||
```
|
||||
|
||||
### 2. Config-Files auf Server kopieren
|
||||
|
||||
```bash
|
||||
# Falls docker-compose.prod.yml oder .env geändert wurden
|
||||
scp docker-compose.prod.yml deploy@94.16.110.151:/home/deploy/framework/
|
||||
scp .env.production deploy@94.16.110.151:/home/deploy/framework/.env
|
||||
```
|
||||
|
||||
### 3. Auf Server deployen
|
||||
|
||||
```bash
|
||||
ssh deploy@94.16.110.151
|
||||
cd /home/deploy/framework
|
||||
|
||||
# Pull und Deploy
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
### 4. Status checken
|
||||
|
||||
```bash
|
||||
# Container Status
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml ps
|
||||
|
||||
# Logs anschauen
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml logs -f web php
|
||||
|
||||
# Supervisor Status (im web container)
|
||||
docker exec web supervisorctl status
|
||||
```
|
||||
|
||||
### 5. Application testen
|
||||
|
||||
```bash
|
||||
# Von lokaler Maschine (via WireGuard)
|
||||
curl -k -I https://94.16.110.151:8443/
|
||||
|
||||
# Erwartetes Ergebnis:
|
||||
# HTTP/2 200
|
||||
# server: nginx
|
||||
```
|
||||
|
||||
## Rollback
|
||||
|
||||
Falls Probleme auftreten:
|
||||
|
||||
```bash
|
||||
# Auf Server
|
||||
cd /home/deploy/framework
|
||||
|
||||
# Vorheriges Image ID finden
|
||||
docker images 94.16.110.151:5000/framework
|
||||
|
||||
# Zu spezifischem Image wechseln
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml down
|
||||
docker tag 94.16.110.151:5000/framework@sha256:<old-digest> 94.16.110.151:5000/framework:latest
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
## Monitoring URLs
|
||||
|
||||
**Zugang nur via WireGuard VPN (10.8.0.1)**:
|
||||
|
||||
- Prometheus: http://10.8.0.1:9090
|
||||
- Grafana: http://10.8.0.1:3000 (admin / $GRAFANA_PASSWORD)
|
||||
- Portainer: https://10.8.0.1:9443
|
||||
|
||||
## Watchtower Auto-Updates
|
||||
|
||||
Watchtower überwacht automatisch und updated Container mit neuem Image (alle 5 Minuten).
|
||||
|
||||
**Status checken**:
|
||||
```bash
|
||||
docker logs watchtower
|
||||
```
|
||||
|
||||
**Manuell triggern**:
|
||||
```bash
|
||||
# Watchtower neu starten (triggert sofortigen Check)
|
||||
docker restart watchtower
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container nicht healthy
|
||||
|
||||
```bash
|
||||
# Logs anschauen
|
||||
docker logs web
|
||||
docker logs php
|
||||
|
||||
# Im Container debuggen
|
||||
docker exec -it web sh
|
||||
docker exec -it php sh
|
||||
|
||||
# Supervisor Status
|
||||
docker exec web supervisorctl status
|
||||
|
||||
# Nginx/PHP-FPM Prozesse
|
||||
docker exec web ps aux | grep -E 'nginx|php-fpm'
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
```bash
|
||||
# PostgreSQL Connection testen
|
||||
docker exec php php -r "new PDO('pgsql:host=db;dbname=framework_db', 'framework_user', 'password');"
|
||||
|
||||
# Database Logs
|
||||
docker logs db
|
||||
|
||||
# In Database connecten
|
||||
docker exec -it db psql -U framework_user -d framework_db
|
||||
```
|
||||
|
||||
### Redis Connection Issues
|
||||
|
||||
```bash
|
||||
# Redis Connection testen
|
||||
docker exec php php -r "var_dump((new Redis())->connect('redis', 6379));"
|
||||
|
||||
# Redis Logs
|
||||
docker logs redis
|
||||
|
||||
# Redis CLI
|
||||
docker exec -it redis redis-cli
|
||||
```
|
||||
|
||||
## Maintenance Commands
|
||||
|
||||
### Database Backup
|
||||
|
||||
```bash
|
||||
# Manual Backup
|
||||
docker exec db pg_dump -U framework_user framework_db > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
```
|
||||
|
||||
### Logs Cleanup
|
||||
|
||||
```bash
|
||||
# Storage Logs leeren (auf Server)
|
||||
docker exec web sh -c 'rm -rf /var/www/html/storage/logs/*.log'
|
||||
|
||||
# Docker Logs cleanup
|
||||
docker system prune -f
|
||||
docker volume prune -f
|
||||
```
|
||||
|
||||
### Image Cleanup
|
||||
|
||||
```bash
|
||||
# Alte Images entfernen
|
||||
docker image prune -a -f
|
||||
|
||||
# Nur untagged images
|
||||
docker image prune -f
|
||||
```
|
||||
|
||||
## Performance Check
|
||||
|
||||
```bash
|
||||
# Container Resource Usage
|
||||
docker stats
|
||||
|
||||
# PHP-FPM Status
|
||||
docker exec web curl http://localhost/php-fpm-status
|
||||
|
||||
# Nginx Status
|
||||
docker exec web curl http://localhost/nginx-status
|
||||
|
||||
# Database Connections
|
||||
docker exec db psql -U framework_user -d framework_db -c "SELECT count(*) FROM pg_stat_activity;"
|
||||
```
|
||||
|
||||
## SSL Certificate Renewal
|
||||
|
||||
```bash
|
||||
# Let's Encrypt Renewal (auf Server als root)
|
||||
certbot renew
|
||||
docker exec web nginx -s reload
|
||||
```
|
||||
|
||||
## Nützliche Aliases
|
||||
|
||||
Füge zu `~/.bashrc` auf Production Server hinzu:
|
||||
|
||||
```bash
|
||||
alias dc='docker-compose -f docker-compose.yml -f docker-compose.prod.yml'
|
||||
alias dcup='dc up -d'
|
||||
alias dcdown='dc down'
|
||||
alias dcps='dc ps'
|
||||
alias dclogs='dc logs -f'
|
||||
alias dcrestart='dc restart'
|
||||
```
|
||||
|
||||
Dann kannst du einfach verwenden:
|
||||
```bash
|
||||
dcup # Deploy
|
||||
dcps # Status
|
||||
dclogs # Logs anschauen
|
||||
```
|
||||
197
docs/deployment/test-registry-credentials.md
Normal file
197
docs/deployment/test-registry-credentials.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# Docker Registry Credentials Testen
|
||||
|
||||
Dieses Dokument erklärt, wie du die Docker Registry Credentials testen kannst.
|
||||
|
||||
## Lokales Testen
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
1. Docker muss installiert und laufend sein
|
||||
2. Curl muss verfügbar sein (wird automatisch installiert falls fehlend)
|
||||
|
||||
### Verwendung
|
||||
|
||||
```bash
|
||||
# Setze die Credentials als Environment-Variablen
|
||||
export REGISTRY_USER="admin"
|
||||
export REGISTRY_PASSWORD="dein-registry-passwort"
|
||||
|
||||
# Führe das Test-Script aus
|
||||
./scripts/test-registry-credentials.sh
|
||||
```
|
||||
|
||||
### Mit expliziten Werten
|
||||
|
||||
```bash
|
||||
REGISTRY_USER="admin" \
|
||||
REGISTRY_PASSWORD="dein-passwort" \
|
||||
REGISTRY_DOMAIN="registry.michaelschiemer.de" \
|
||||
REGISTRY_HOST="94.16.110.151" \
|
||||
REGISTRY_PORT="5000" \
|
||||
./scripts/test-registry-credentials.sh
|
||||
```
|
||||
|
||||
## Was wird getestet?
|
||||
|
||||
Das Script führt folgende Tests durch:
|
||||
|
||||
### 1. HTTP Connectivity
|
||||
- Testet ob die Registry über HTTP erreichbar ist (`http://94.16.110.151:5000`)
|
||||
- Erwartet Status 401 (Auth erforderlich) oder 200
|
||||
|
||||
### 2. HTTPS Connectivity
|
||||
- Testet ob die Registry über HTTPS erreichbar ist (`https://registry.michaelschiemer.de`)
|
||||
- Erwartet Status 401 (Auth erforderlich) oder 200
|
||||
|
||||
### 3. Docker Login über HTTP
|
||||
- Versucht Docker Login über HTTP
|
||||
- Benötigt `insecure-registry` Konfiguration im Docker-daemon
|
||||
|
||||
### 4. Docker Login über HTTPS
|
||||
- Versucht Docker Login über HTTPS
|
||||
- Keine zusätzliche Konfiguration nötig (empfohlen)
|
||||
|
||||
### 5. Registry API Zugriff
|
||||
- Testet ob die Registry API funktioniert
|
||||
- Listet verfügbare Repositories auf
|
||||
|
||||
## Test in CI/CD
|
||||
|
||||
### Via Gitea Workflow
|
||||
|
||||
Das Script kann auch in einem Gitea Workflow verwendet werden:
|
||||
|
||||
```yaml
|
||||
- name: Test Registry Credentials
|
||||
shell: bash
|
||||
env:
|
||||
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
run: |
|
||||
./scripts/test-registry-credentials.sh
|
||||
```
|
||||
|
||||
### Workflow ausführen
|
||||
|
||||
Es gibt einen dedizierten Workflow `.gitea/workflows/test-registry.yml`:
|
||||
|
||||
1. Gehe zu: **Actions** → **Test Registry Credentials**
|
||||
2. Klicke auf **Run workflow**
|
||||
3. Der Workflow testet automatisch die Credentials aus Gitea Secrets
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problem: "REGISTRY_PASSWORD ist nicht gesetzt"
|
||||
|
||||
**Lösung:**
|
||||
```bash
|
||||
export REGISTRY_PASSWORD="dein-passwort"
|
||||
```
|
||||
|
||||
### Problem: "Unauthorized (401)" beim Login
|
||||
|
||||
**Ursache:** Falsche Credentials
|
||||
|
||||
**Lösung:**
|
||||
1. Prüfe `REGISTRY_USER` - sollte `admin` sein (oder der richtige Username)
|
||||
2. Prüfe `REGISTRY_PASSWORD` - muss mit dem Passwort in `deployment/stacks/registry/auth/htpasswd` übereinstimmen
|
||||
3. Prüfe Gitea Secrets:
|
||||
- Repository → Settings → Secrets
|
||||
- Stelle sicher, dass `REGISTRY_USER` und `REGISTRY_PASSWORD` korrekt sind
|
||||
|
||||
### Problem: "HTTP response to HTTPS client"
|
||||
|
||||
**Ursache:** Docker versucht HTTPS, aber Registry läuft auf HTTP
|
||||
|
||||
**Lösung:**
|
||||
- Für HTTP: Docker-daemon muss mit `--insecure-registry` konfiguriert werden
|
||||
- Oder verwende HTTPS-Zugriff über `registry.michaelschiemer.de` (empfohlen)
|
||||
|
||||
### Problem: "Registry nicht erreichbar"
|
||||
|
||||
**Ursache:** Registry läuft nicht oder Netzwerk-Problem
|
||||
|
||||
**Lösung:**
|
||||
```bash
|
||||
# Prüfe ob Registry läuft
|
||||
docker ps | grep registry
|
||||
|
||||
# Prüfe Registry-Logs
|
||||
docker logs registry
|
||||
|
||||
# Prüfe Netzwerk
|
||||
curl -v http://94.16.110.151:5000/v2/
|
||||
```
|
||||
|
||||
### Problem: "404" bei HTTPS
|
||||
|
||||
**Ursache:** Traefik-Routing ist nicht richtig konfiguriert
|
||||
|
||||
**Lösung:**
|
||||
1. Prüfe Traefik Labels in `deployment/stacks/registry/docker-compose.yml`
|
||||
2. Prüfe ob Registry im `traefik-public` Netzwerk ist
|
||||
3. Prüfe DNS-Konfiguration für `registry.michaelschiemer.de`
|
||||
|
||||
## Passwort prüfen/ändern
|
||||
|
||||
### Passwort auf dem Server prüfen
|
||||
|
||||
```bash
|
||||
ssh deploy@94.16.110.151
|
||||
cd ~/deployment/stacks/registry
|
||||
cat auth/htpasswd
|
||||
```
|
||||
|
||||
### Neues Passwort setzen
|
||||
|
||||
```bash
|
||||
ssh deploy@94.16.110.151
|
||||
cd ~/deployment/stacks/registry
|
||||
|
||||
# Neues Passwort setzen
|
||||
htpasswd -B auth/htpasswd admin
|
||||
|
||||
# Registry neu starten
|
||||
docker compose restart registry
|
||||
```
|
||||
|
||||
Dann in Gitea Secrets aktualisieren:
|
||||
- Repository → Settings → Secrets
|
||||
- `REGISTRY_PASSWORD` mit neuem Passwort aktualisieren
|
||||
|
||||
## Script-Output
|
||||
|
||||
### Erfolgreich
|
||||
|
||||
```
|
||||
✅ Docker ist verfügbar
|
||||
✅ curl ist verfügbar
|
||||
✅ Registry erreichbar über HTTPS (Status: 401 - Auth erforderlich, das ist gut!)
|
||||
✅ Docker Login erfolgreich!
|
||||
✅ Credentials sind korrekt und funktionieren!
|
||||
```
|
||||
|
||||
### Fehlgeschlagen
|
||||
|
||||
```
|
||||
❌ Docker Login fehlgeschlagen (Exit Code: 1)
|
||||
⚠️ Fehler: Unauthorized (401)
|
||||
ℹ️ Die Credentials sind falsch:
|
||||
ℹ️ - Username: admin
|
||||
ℹ️ - Password Länge: 24 Zeichen
|
||||
```
|
||||
|
||||
## Integration in CI/CD
|
||||
|
||||
Das Script kann in jedem Workflow-Step verwendet werden:
|
||||
|
||||
```yaml
|
||||
- name: Verify Registry Access
|
||||
env:
|
||||
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
run: |
|
||||
./scripts/test-registry-credentials.sh
|
||||
```
|
||||
|
||||
Falls das Script fehlschlägt (Exit Code 1), wird der Workflow gestoppt und du bekommst klare Fehlermeldungen.
|
||||
@@ -1,581 +0,0 @@
|
||||
# Production Deployment Troubleshooting Checklist
|
||||
|
||||
Systematische Problemlösung für häufige Deployment-Issues.
|
||||
|
||||
## Issue 1: Supervisor Log File Permission Denied
|
||||
|
||||
### Symptom
|
||||
```
|
||||
PermissionError: [Errno 13] Permission denied: '/var/log/supervisor/supervisord.log'
|
||||
```
|
||||
|
||||
Container startet nicht, Supervisor kann Logfile nicht schreiben.
|
||||
|
||||
### Diagnose
|
||||
```bash
|
||||
docker logs web # Zeigt Permission Error
|
||||
docker exec web ls -la /var/log/supervisor/ # Directory existiert nicht oder keine Permissions
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
- Supervisor versucht in `/var/log/supervisor/supervisord.log` zu schreiben
|
||||
- Directory existiert nicht oder keine Write-Permissions
|
||||
- Auch als root problematisch in containerisierter Umgebung
|
||||
|
||||
### Lösung 1 (FUNKTIONIERT NICHT)
|
||||
❌ **Versuch**: `/proc/self/fd/1` verwenden
|
||||
|
||||
`docker/supervisor/supervisord.conf`:
|
||||
```ini
|
||||
logfile=/proc/self/fd/1
|
||||
```
|
||||
|
||||
**Fehler**: `PermissionError: [Errno 13] Permission denied: '/proc/self/fd/1'`
|
||||
|
||||
**Grund**: Python's logging library (verwendet von Supervisor) kann `/proc/self/fd/1` oder `/dev/stdout` nicht im append-mode öffnen.
|
||||
|
||||
### Lösung 2 (ERFOLGREICH)
|
||||
✅ **Fix**: `/dev/null` mit `silent=false`
|
||||
|
||||
`docker/supervisor/supervisord.conf`:
|
||||
```ini
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
silent=false # WICHTIG: Logging trotz /dev/null
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/var/run/supervisord.pid
|
||||
loglevel=info
|
||||
```
|
||||
|
||||
**Warum funktioniert das?**
|
||||
- `logfile=/dev/null`: Kein File-Logging
|
||||
- `silent=false`: Supervisor loggt nach stdout/stderr
|
||||
- Logs erscheinen in `docker logs web`
|
||||
|
||||
### Verification
|
||||
```bash
|
||||
docker logs web
|
||||
# Output:
|
||||
# 2025-10-28 16:29:59,976 INFO supervisord started with pid 1
|
||||
# 2025-10-28 16:30:00,980 INFO spawned: 'nginx' with pid 7
|
||||
# 2025-10-28 16:30:00,982 INFO spawned: 'php-fpm' with pid 8
|
||||
# 2025-10-28 16:30:02,077 INFO success: nginx entered RUNNING state
|
||||
# 2025-10-28 16:30:02,077 INFO success: php-fpm entered RUNNING state
|
||||
```
|
||||
|
||||
### Related Files
|
||||
- `docker/supervisor/supervisord.conf`
|
||||
- `Dockerfile.production` (COPY supervisord.conf)
|
||||
|
||||
---
|
||||
|
||||
## Issue 2: Web Container EACCES Errors
|
||||
|
||||
### Symptom
|
||||
```
|
||||
2025-10-28 16:16:52,152 CRIT could not write pidfile /var/run/supervisord.pid
|
||||
2025-10-28 16:16:53,154 INFO spawnerr: unknown error making dispatchers for 'nginx': EACCES
|
||||
2025-10-28 16:16:53,154 INFO spawnerr: unknown error making dispatchers for 'php-fpm': EACCES
|
||||
```
|
||||
|
||||
### Diagnose
|
||||
```bash
|
||||
# Container User checken
|
||||
docker exec web whoami
|
||||
# Falls nicht "root", dann ist das der Issue
|
||||
|
||||
# Docker Compose Config checken
|
||||
docker inspect web | grep -i user
|
||||
# Zeigt inherited user von base config
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
- `web` service in `docker-compose.prod.yml` hat **kein** `user: root` gesetzt
|
||||
- Inherited `user: 1000:1000` oder `user: www-data` von base `docker-compose.yml`
|
||||
- Supervisor benötigt root um nginx/php-fpm master processes zu starten
|
||||
|
||||
### Lösung
|
||||
✅ **Fix**: `user: root` explizit setzen
|
||||
|
||||
`docker-compose.prod.yml`:
|
||||
```yaml
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
user: root # ← HINZUFÜGEN
|
||||
# ... rest der config
|
||||
```
|
||||
|
||||
Auch für `php` und `queue-worker` services hinzufügen:
|
||||
```yaml
|
||||
php:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
user: root # ← HINZUFÜGEN
|
||||
|
||||
queue-worker:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
user: root # ← HINZUFÜGEN
|
||||
```
|
||||
|
||||
### Warum user: root?
|
||||
- **Container läuft als root**: Supervisor master process
|
||||
- **Nginx master**: root (worker processes als www-data via nginx.conf)
|
||||
- **PHP-FPM master**: root (pool workers als www-data via php-fpm.conf)
|
||||
|
||||
`docker/php/zz-docker.production.conf`:
|
||||
```ini
|
||||
[www]
|
||||
user = www-data # ← Worker processes laufen als www-data
|
||||
group = www-data
|
||||
```
|
||||
|
||||
### Verification
|
||||
```bash
|
||||
docker exec web whoami
|
||||
# root
|
||||
|
||||
docker exec web ps aux | grep -E 'nginx|php-fpm'
|
||||
# root 1 supervisord
|
||||
# root 7 nginx: master process
|
||||
# www-data 10 nginx: worker process
|
||||
# root 8 php-fpm: master process
|
||||
# www-data 11 php-fpm: pool www
|
||||
```
|
||||
|
||||
### Related Files
|
||||
- `docker-compose.prod.yml` (web, php, queue-worker services)
|
||||
- `docker/php/zz-docker.production.conf`
|
||||
- `docker/nginx/nginx.production.conf`
|
||||
|
||||
---
|
||||
|
||||
## Issue 3: Docker Entrypoint Override funktioniert nicht
|
||||
|
||||
### Symptom
|
||||
Container command zeigt Entrypoint prepended:
|
||||
```bash
|
||||
docker ps
|
||||
# COMMAND: "/usr/local/bin/docker-entrypoint.sh /usr/bin/supervisord -c ..."
|
||||
```
|
||||
|
||||
Supervisor wird nicht direkt gestartet, sondern durch einen wrapper script.
|
||||
|
||||
### Diagnose
|
||||
```bash
|
||||
# Container Command checken
|
||||
docker inspect web --format='{{.Config.Entrypoint}}'
|
||||
# [/usr/local/bin/docker-entrypoint.sh]
|
||||
|
||||
docker inspect web --format='{{.Config.Cmd}}'
|
||||
# [/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf]
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
1. Base `docker-compose.yml` hat `web` service mit separate build:
|
||||
```yaml
|
||||
web:
|
||||
build:
|
||||
context: docker/nginx
|
||||
dockerfile: Dockerfile
|
||||
```
|
||||
|
||||
2. Production override setzt `image:` aber cleared **nicht** den inherited ENTRYPOINT:
|
||||
```yaml
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
command: ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
```
|
||||
|
||||
3. Base PHP image hat ENTRYPOINT der prepended wird
|
||||
4. Docker Compose merge: ENTRYPOINT + CMD = final command
|
||||
|
||||
### Lösung - Iteration 1 (FUNKTIONIERT NICHT)
|
||||
❌ **Versuch**: Nur `command:` setzen
|
||||
|
||||
`docker-compose.prod.yml`:
|
||||
```yaml
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
command: ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
```
|
||||
|
||||
**Result**: Entrypoint wird trotzdem prepended
|
||||
|
||||
### Lösung - Iteration 2 (FUNKTIONIERT NICHT)
|
||||
❌ **Versuch**: `pull_policy: always` hinzufügen
|
||||
|
||||
`docker-compose.prod.yml`:
|
||||
```yaml
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
pull_policy: always # Force registry pull
|
||||
command: ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
```
|
||||
|
||||
**Result**: Image wird von Registry gepullt, aber Entrypoint wird trotzdem prepended
|
||||
|
||||
### Lösung - Iteration 3 (ERFOLGREICH)
|
||||
✅ **Fix**: `entrypoint: []` explizit clearen
|
||||
|
||||
`docker-compose.prod.yml`:
|
||||
```yaml
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
pull_policy: always # Always pull from registry, never build
|
||||
entrypoint: [] # ← WICHTIG: Entrypoint clearen
|
||||
command: ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
user: root
|
||||
```
|
||||
|
||||
**Warum `entrypoint: []`?**
|
||||
- Leeres Array cleared den inherited entrypoint komplett
|
||||
- `command:` wird dann direkt als PID 1 gestartet
|
||||
- Keine wrapper scripts, keine indirection
|
||||
|
||||
### Verification
|
||||
```bash
|
||||
docker inspect web --format='{{.Config.Entrypoint}}'
|
||||
# [] ← Leer!
|
||||
|
||||
docker inspect web --format='{{.Config.Cmd}}'
|
||||
# [/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf]
|
||||
|
||||
docker exec web ps aux
|
||||
# PID 1: /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
# Kein entrypoint wrapper!
|
||||
```
|
||||
|
||||
### Related Files
|
||||
- `docker-compose.prod.yml` (web service)
|
||||
|
||||
### Docker Compose Override Rules
|
||||
```
|
||||
Base Config + Override = Final Config
|
||||
|
||||
Base:
|
||||
web:
|
||||
build: docker/nginx
|
||||
→ inherited ENTRYPOINT from base image
|
||||
|
||||
Override (insufficient):
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
command: [...]
|
||||
→ ENTRYPOINT still prepended to command
|
||||
|
||||
Override (correct):
|
||||
web:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
entrypoint: [] ← Clears inherited entrypoint
|
||||
command: [...] ← Runs directly as PID 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Issue 4: Queue Worker Container Restarts
|
||||
|
||||
### Symptom
|
||||
```bash
|
||||
docker ps
|
||||
# queue-worker Restarting (1) 5 seconds ago
|
||||
```
|
||||
|
||||
Container restart loop, nie healthy.
|
||||
|
||||
### Diagnose
|
||||
```bash
|
||||
docker logs queue-worker
|
||||
# Error: /var/www/html/worker.php not found
|
||||
# oder
|
||||
# php: command not found
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
Base `docker-compose.yml` hat Queue Worker Command für Development:
|
||||
```yaml
|
||||
queue-worker:
|
||||
command: ["php", "/var/www/html/worker.php"]
|
||||
```
|
||||
|
||||
`worker.php` existiert nicht im Production Image.
|
||||
|
||||
### Lösung - Option 1: Service deaktivieren
|
||||
✅ **Quick Fix**: Queue Worker deaktivieren
|
||||
|
||||
`docker-compose.prod.yml`:
|
||||
```yaml
|
||||
queue-worker:
|
||||
deploy:
|
||||
replicas: 0 # Disable service
|
||||
```
|
||||
|
||||
### Lösung - Option 2: Richtigen Command setzen
|
||||
✅ **Proper Fix**: Console Command verwenden
|
||||
|
||||
`docker-compose.prod.yml`:
|
||||
```yaml
|
||||
queue-worker:
|
||||
image: 94.16.110.151:5000/framework:latest
|
||||
user: root
|
||||
command: ["php", "/var/www/html/console.php", "queue:work"]
|
||||
# oder für Supervisor-managed:
|
||||
# entrypoint: []
|
||||
# command: ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/queue-worker-supervisord.conf"]
|
||||
```
|
||||
|
||||
### Verification
|
||||
```bash
|
||||
docker logs queue-worker
|
||||
# [timestamp] INFO Queue worker started
|
||||
# [timestamp] INFO Processing job: ...
|
||||
```
|
||||
|
||||
### Related Files
|
||||
- `docker-compose.yml` (base queue-worker definition)
|
||||
- `docker-compose.prod.yml` (production override)
|
||||
- `console.php` (framework console application)
|
||||
|
||||
---
|
||||
|
||||
## Issue 5: HTTP Port 80 nicht erreichbar
|
||||
|
||||
### Symptom
|
||||
```bash
|
||||
curl http://94.16.110.151:8888/
|
||||
# curl: (7) Failed to connect to 94.16.110.151 port 8888: Connection refused
|
||||
|
||||
docker exec web curl http://localhost/
|
||||
# curl: (7) Failed to connect to localhost port 80: Connection refused
|
||||
```
|
||||
|
||||
### Diagnose
|
||||
```bash
|
||||
# Nginx listening ports checken
|
||||
docker exec web netstat -tlnp | grep nginx
|
||||
# Zeigt nur: 0.0.0.0:443
|
||||
|
||||
# Nginx Config checken
|
||||
docker exec web cat /etc/nginx/http.d/default.conf
|
||||
# Kein "listen 80;" block
|
||||
```
|
||||
|
||||
### Root Cause - Option 1: Intentional HTTPS-only
|
||||
Möglicherweise ist HTTP absichtlich disabled (Security Best Practice).
|
||||
|
||||
### Root Cause - Option 2: Missing HTTP Block
|
||||
Nginx config hat keinen HTTP listener, nur HTTPS.
|
||||
|
||||
### Lösung - HTTP→HTTPS Redirect hinzufügen
|
||||
✅ **Fix**: HTTP Redirect konfigurieren
|
||||
|
||||
`docker/nginx/default.production.conf`:
|
||||
```nginx
|
||||
# HTTP → HTTPS Redirect
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS Server
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name _;
|
||||
|
||||
ssl_certificate /var/www/ssl/cert.pem;
|
||||
ssl_certificate_key /var/www/ssl/key.pem;
|
||||
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass php:9000;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Verification
|
||||
```bash
|
||||
curl -I http://94.16.110.151:8888/
|
||||
# HTTP/1.1 301 Moved Permanently
|
||||
# Location: https://94.16.110.151:8888/
|
||||
|
||||
curl -k -I https://94.16.110.151:8443/
|
||||
# HTTP/2 200
|
||||
# server: nginx
|
||||
```
|
||||
|
||||
### Related Files
|
||||
- `docker/nginx/default.production.conf`
|
||||
- `Dockerfile.production` (COPY nginx config)
|
||||
|
||||
---
|
||||
|
||||
## General Debugging Commands
|
||||
|
||||
### Container Inspection
|
||||
```bash
|
||||
# Alle Container Status
|
||||
docker-compose -f docker-compose.yml -f docker-compose.prod.yml ps
|
||||
|
||||
# Container Details
|
||||
docker inspect web
|
||||
|
||||
# Container Logs
|
||||
docker logs -f web
|
||||
docker logs --tail 100 web
|
||||
|
||||
# Inside Container
|
||||
docker exec -it web sh
|
||||
docker exec -it php sh
|
||||
```
|
||||
|
||||
### Supervisor Debugging
|
||||
```bash
|
||||
# Supervisor Status
|
||||
docker exec web supervisorctl status
|
||||
|
||||
# Supervisor Logs
|
||||
docker exec web tail -f /dev/null # Logs gehen nach stdout/stderr
|
||||
|
||||
# Supervisor Config testen
|
||||
docker exec web supervisord -c /etc/supervisor/conf.d/supervisord.conf -n
|
||||
```
|
||||
|
||||
### Nginx Debugging
|
||||
```bash
|
||||
# Nginx Config testen
|
||||
docker exec web nginx -t
|
||||
|
||||
# Nginx reload
|
||||
docker exec web nginx -s reload
|
||||
|
||||
# Nginx listening ports
|
||||
docker exec web netstat -tlnp | grep nginx
|
||||
|
||||
# Nginx processes
|
||||
docker exec web ps aux | grep nginx
|
||||
```
|
||||
|
||||
### PHP-FPM Debugging
|
||||
```bash
|
||||
# PHP-FPM Status
|
||||
docker exec web curl http://localhost/php-fpm-status
|
||||
|
||||
# PHP-FPM Config testen
|
||||
docker exec web php-fpm -t
|
||||
|
||||
# PHP-FPM processes
|
||||
docker exec web ps aux | grep php-fpm
|
||||
|
||||
# PHP Version
|
||||
docker exec web php -v
|
||||
|
||||
# PHP Modules
|
||||
docker exec web php -m
|
||||
```
|
||||
|
||||
### Network Debugging
|
||||
```bash
|
||||
# Port listening
|
||||
docker exec web netstat -tlnp
|
||||
|
||||
# DNS resolution
|
||||
docker exec web nslookup db
|
||||
docker exec web nslookup redis
|
||||
|
||||
# Network connectivity
|
||||
docker exec web ping db
|
||||
docker exec web ping redis
|
||||
|
||||
# HTTP request
|
||||
docker exec web curl http://localhost/
|
||||
```
|
||||
|
||||
### Database Debugging
|
||||
```bash
|
||||
# PostgreSQL Connection
|
||||
docker exec php php -r "new PDO('pgsql:host=db;dbname=framework_db', 'framework_user', 'password');"
|
||||
|
||||
# Database Logs
|
||||
docker logs db
|
||||
|
||||
# Connect to DB
|
||||
docker exec -it db psql -U framework_user -d framework_db
|
||||
|
||||
# Check connections
|
||||
docker exec db psql -U framework_user -d framework_db -c "SELECT count(*) FROM pg_stat_activity;"
|
||||
```
|
||||
|
||||
### Performance Monitoring
|
||||
```bash
|
||||
# Container Resource Usage
|
||||
docker stats
|
||||
|
||||
# Disk Usage
|
||||
docker system df
|
||||
|
||||
# Image Sizes
|
||||
docker images
|
||||
|
||||
# Volume Sizes
|
||||
docker system df -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist für erfolgreichen Deploy
|
||||
|
||||
### Pre-Deployment
|
||||
- [ ] Image gebaut: `docker build -f Dockerfile.production -t 94.16.110.151:5000/framework:latest .`
|
||||
- [ ] Image gepusht: `docker push 94.16.110.151:5000/framework:latest`
|
||||
- [ ] Registry verfügbar: `curl http://94.16.110.151:5000/v2/_catalog`
|
||||
- [ ] WireGuard VPN aktiv: `wg show`
|
||||
- [ ] `.env.production` auf Server aktuell
|
||||
- [ ] `docker-compose.prod.yml` auf Server aktuell
|
||||
|
||||
### Deployment
|
||||
- [ ] SSH auf Server: `ssh deploy@94.16.110.151`
|
||||
- [ ] Image pullen: `docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull`
|
||||
- [ ] Stack starten: `docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d`
|
||||
|
||||
### Post-Deployment Verification
|
||||
- [ ] Container laufen: `docker-compose ps` zeigt alle "Up (healthy)"
|
||||
- [ ] Supervisor Status: `docker exec web supervisorctl status` zeigt nginx/php-fpm RUNNING
|
||||
- [ ] Nginx lauscht: `docker exec web netstat -tlnp | grep :443`
|
||||
- [ ] PHP-FPM lauscht: `docker exec web netstat -tlnp | grep :9000`
|
||||
- [ ] Application erreichbar: `curl -k -I https://94.16.110.151:8443/` → HTTP/2 200
|
||||
- [ ] Database erreichbar: `docker exec php php -r "new PDO(...);"`
|
||||
- [ ] Redis erreichbar: `docker exec php php -r "new Redis()->connect('redis', 6379);"`
|
||||
- [ ] Logs sauber: `docker logs web` zeigt keine Errors
|
||||
|
||||
### Monitoring
|
||||
- [ ] Prometheus: http://10.8.0.1:9090 erreichbar
|
||||
- [ ] Grafana: http://10.8.0.1:3000 erreichbar
|
||||
- [ ] Portainer: https://10.8.0.1:9443 erreichbar
|
||||
- [ ] Watchtower aktiv: `docker logs watchtower` zeigt Checks
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Häufigste Fehlerursachen
|
||||
1. **Supervisor Logging**: Verwende `logfile=/dev/null` + `silent=false`
|
||||
2. **User Permissions**: Setze `user: root` in docker-compose.prod.yml
|
||||
3. **Entrypoint Override**: Setze `entrypoint: []` um inherited entrypoint zu clearen
|
||||
4. **Pull Policy**: Verwende `pull_policy: always` um registry image zu forcen
|
||||
|
||||
### Wichtigste Config-Änderungen
|
||||
- `docker/supervisor/supervisord.conf`: `logfile=/dev/null`, `silent=false`
|
||||
- `docker-compose.prod.yml`: `user: root`, `entrypoint: []`, `pull_policy: always`
|
||||
- `docker/php/zz-docker.production.conf`: `user = www-data`, `group = www-data`
|
||||
Reference in New Issue
Block a user