301 lines
7.3 KiB
Markdown
301 lines
7.3 KiB
Markdown
# 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
|
|
``` |