Files
Rezepte/DEPLOYMENT.md

7.2 KiB

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

git clone <your-repository-url> /opt/rezepte
cd /opt/rezepte

2. Produktions-Umgebung konfigurieren

Environment-Datei erstellen

cp .env.example .env.production

.env.production anpassen:

# Database
DATABASE_URL="mysql://rezepte_user:secure_password_here@mysql:3306/rezepte"

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

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: rezepte-mysql-prod
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: rezepte
      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: ./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
      - 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: ./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

# 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)

# /etc/nginx/sites-available/rezepte
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:

#!/bin/bash
set -e

echo "🚀 Deploying Rezepte..."

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

#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/opt/backups/rezepte"

mkdir -p $BACKUP_DIR

# Database backup
docker exec rezepte-mysql-prod mysqldump -u root -psuper_secure_root_password rezepte > $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:

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

docker-compose -f docker-compose.production.yml ps

7. Automatische Updates (Optional)

Crontab für automatische Backups:

# Täglich um 2 Uhr
0 2 * * * /opt/rezepte/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:

docker-compose -f docker-compose.production.yml logs [service-name]

Database-Probleme:

# In MySQL-Container einloggen
docker exec -it rezepte-mysql-prod mysql -u root -p

# Database-Status prüfen
SHOW DATABASES;
USE rezepte;
SHOW TABLES;

Permission-Probleme:

# Upload-Ordner Permissions
docker exec -it rezepte-backend-prod chown -R backend:nodejs /app/uploads