Docker mit traefik und portainer
This commit is contained in:
301
DEPLOYMENT.md
Normal file
301
DEPLOYMENT.md
Normal file
@@ -0,0 +1,301 @@
|
||||
# Deployment auf externem Server
|
||||
|
||||
## Voraussetzungen auf dem Server
|
||||
- Docker und Docker Compose installiert
|
||||
- Git installiert
|
||||
- Port 80 und/oder 443 für Web-Traffic geöffnet
|
||||
- Optional: Reverse Proxy (nginx/Apache) für SSL-Termination
|
||||
|
||||
## 1. Repository auf Server klonen
|
||||
```bash
|
||||
git clone <your-repository-url> /opt/rezepte-klaus
|
||||
cd /opt/rezepte-klaus
|
||||
```
|
||||
|
||||
## 2. Produktions-Umgebung konfigurieren
|
||||
|
||||
### Environment-Datei erstellen
|
||||
```bash
|
||||
cp .env.example .env.production
|
||||
```
|
||||
|
||||
### .env.production anpassen:
|
||||
```env
|
||||
# Database
|
||||
DATABASE_URL="mysql://rezepte_user:secure_password_here@mysql:3306/rezepte_klaus"
|
||||
|
||||
# Security
|
||||
JWT_SECRET="your-super-secure-jwt-secret-min-32-chars"
|
||||
|
||||
# CORS - Ihre Domain(s) eintragen
|
||||
CORS_ORIGIN="https://yourdomain.com"
|
||||
|
||||
# Environment
|
||||
NODE_ENV=production
|
||||
|
||||
# Uploads
|
||||
UPLOAD_DIR=/app/uploads
|
||||
MAX_UPLOAD_SIZE=10mb
|
||||
|
||||
# Server
|
||||
PORT=3001
|
||||
```
|
||||
|
||||
## 3. Docker Compose für Produktion anpassen
|
||||
|
||||
### docker-compose.production.yml erstellen:
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: rezepte-mysql-prod
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_DATABASE: rezepte_klaus
|
||||
MYSQL_USER: rezepte_user
|
||||
MYSQL_PASSWORD: secure_password_here
|
||||
MYSQL_ROOT_PASSWORD: super_secure_root_password
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./Rezepte.sql:/docker-entrypoint-initdb.d/01-rezepte.sql:ro
|
||||
- ./ingredients.sql:/docker-entrypoint-initdb.d/02-ingredients.sql:ro
|
||||
- ./Zubereitung.sql:/docker-entrypoint-initdb.d/03-zubereitung.sql:ro
|
||||
- ./rezepte_bilder.sql:/docker-entrypoint-initdb.d/04-bilder.sql:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
networks:
|
||||
- rezepte-network
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./nodejs-version/backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: rezepte-backend-prod
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=mysql://rezepte_user:secure_password_here@mysql:3306/rezepte_klaus
|
||||
- JWT_SECRET=your-super-secure-jwt-secret-min-32-chars
|
||||
- CORS_ORIGIN=https://yourdomain.com
|
||||
- PORT=3001
|
||||
volumes:
|
||||
- uploads_data:/app/uploads
|
||||
- ./upload:/app/legacy-uploads:ro
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- rezepte-network
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./nodejs-version/frontend
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- VITE_API_BASE_URL=https://yourdomain.com/api
|
||||
container_name: rezepte-frontend-prod
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443" # Wenn SSL direkt im Container
|
||||
volumes:
|
||||
- ./ssl:/etc/nginx/ssl:ro # SSL-Zertifikate
|
||||
depends_on:
|
||||
- backend
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
networks:
|
||||
- rezepte-network
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
driver: local
|
||||
uploads_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
rezepte-network:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## 4. SSL/HTTPS einrichten
|
||||
|
||||
### Option A: Let's Encrypt mit Certbot
|
||||
```bash
|
||||
# Certbot installieren
|
||||
sudo apt update
|
||||
sudo apt install certbot
|
||||
|
||||
# SSL-Zertifikat erstellen
|
||||
sudo certbot certonly --standalone -d yourdomain.com
|
||||
|
||||
# Zertifikate kopieren
|
||||
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem ./ssl/
|
||||
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem ./ssl/
|
||||
```
|
||||
|
||||
### Option B: Reverse Proxy (empfohlen)
|
||||
```nginx
|
||||
# /etc/nginx/sites-available/rezepte-klaus
|
||||
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;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
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 /api/ {
|
||||
proxy_pass http://localhost:3001;
|
||||
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 /uploads/ {
|
||||
proxy_pass http://localhost:3001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Deployment-Skripte
|
||||
|
||||
### deploy.sh erstellen:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🚀 Deploying Rezepte Klaus..."
|
||||
|
||||
# Git pull latest changes
|
||||
git pull origin main
|
||||
|
||||
# Build and start containers
|
||||
docker-compose -f docker-compose.production.yml down
|
||||
docker-compose -f docker-compose.production.yml up --build -d
|
||||
|
||||
# Health check
|
||||
echo "⏳ Waiting for services to start..."
|
||||
sleep 30
|
||||
|
||||
# Check if all services are healthy
|
||||
if docker-compose -f docker-compose.production.yml ps | grep -q "Up (healthy)"; then
|
||||
echo "✅ Deployment successful!"
|
||||
echo "🌐 Application available at: https://yourdomain.com"
|
||||
else
|
||||
echo "❌ Deployment failed! Check logs:"
|
||||
docker-compose -f docker-compose.production.yml logs
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### backup.sh erstellen:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_DIR="/opt/backups/rezepte-klaus"
|
||||
|
||||
mkdir -p $BACKUP_DIR
|
||||
|
||||
# Database backup
|
||||
docker exec rezepte-mysql-prod mysqldump -u root -psuper_secure_root_password rezepte_klaus > $BACKUP_DIR/database_$DATE.sql
|
||||
|
||||
# Uploads backup
|
||||
docker cp rezepte-backend-prod:/app/uploads $BACKUP_DIR/uploads_$DATE
|
||||
|
||||
# Keep only last 7 backups
|
||||
find $BACKUP_DIR -name "database_*.sql" -mtime +7 -delete
|
||||
find $BACKUP_DIR -name "uploads_*" -mtime +7 -exec rm -rf {} +
|
||||
|
||||
echo "✅ Backup completed: $BACKUP_DIR"
|
||||
```
|
||||
|
||||
## 6. Monitoring und Logs
|
||||
|
||||
### Logs anzeigen:
|
||||
```bash
|
||||
# Alle Services
|
||||
docker-compose -f docker-compose.production.yml logs -f
|
||||
|
||||
# Nur Backend
|
||||
docker-compose -f docker-compose.production.yml logs -f backend
|
||||
|
||||
# Nur Frontend
|
||||
docker-compose -f docker-compose.production.yml logs -f frontend
|
||||
```
|
||||
|
||||
### Service-Status prüfen:
|
||||
```bash
|
||||
docker-compose -f docker-compose.production.yml ps
|
||||
```
|
||||
|
||||
## 7. Automatische Updates (Optional)
|
||||
|
||||
### Crontab für automatische Backups:
|
||||
```bash
|
||||
# Täglich um 2 Uhr
|
||||
0 2 * * * /opt/rezepte-klaus/backup.sh
|
||||
|
||||
# Wöchentlich SSL-Zertifikat erneuern
|
||||
0 3 * * 0 certbot renew --quiet && systemctl reload nginx
|
||||
```
|
||||
|
||||
## 8. Sicherheitshinweise
|
||||
|
||||
1. **Firewall konfigurieren**: Nur Ports 22 (SSH), 80 (HTTP), 443 (HTTPS) öffnen
|
||||
2. **SSH-Key verwenden**: Passwort-Login deaktivieren
|
||||
3. **Regelmäßige Updates**: System und Docker regelmäßig aktualisieren
|
||||
4. **Backup-Strategie**: Automatische Backups einrichten
|
||||
5. **Monitoring**: Log-Monitoring und Alerting einrichten
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container startet nicht:
|
||||
```bash
|
||||
docker-compose -f docker-compose.production.yml logs [service-name]
|
||||
```
|
||||
|
||||
### Database-Probleme:
|
||||
```bash
|
||||
# In MySQL-Container einloggen
|
||||
docker exec -it rezepte-mysql-prod mysql -u root -p
|
||||
|
||||
# Database-Status prüfen
|
||||
SHOW DATABASES;
|
||||
USE rezepte_klaus;
|
||||
SHOW TABLES;
|
||||
```
|
||||
|
||||
### Permission-Probleme:
|
||||
```bash
|
||||
# Upload-Ordner Permissions
|
||||
docker exec -it rezepte-backend-prod chown -R backend:nodejs /app/uploads
|
||||
```
|
||||
Reference in New Issue
Block a user