2026-07-25 23:53:25 +02:00
|
|
|
# LeoCRM Deployment
|
|
|
|
|
|
|
|
|
|
## Quick Start
|
|
|
|
|
|
|
|
|
|
### Option A: Coolify (empfohlen für Produktion)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Einmalig: Umgebungsvariablen setzen
|
|
|
|
|
export COOLIFY_API_TOKEN="dein-token"
|
|
|
|
|
export COOLIFY_APP_UUID="deine-app-uuid"
|
|
|
|
|
|
|
|
|
|
# Deploy
|
|
|
|
|
python scripts/deploy.py
|
|
|
|
|
|
|
|
|
|
# Redeploy (ohne Neubuild)
|
|
|
|
|
python scripts/deploy.py --skip-build
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Das Script macht automatisch:
|
|
|
|
|
1. Coolify Build & Deploy triggern
|
|
|
|
|
2. Persistent Volume in Coolify DB konfigurieren (automatisch, portabel)
|
|
|
|
|
3. Auf healthy Container warten
|
|
|
|
|
4. RLS auf allen Tenant-Tabellen sicherstellen
|
|
|
|
|
5. DB-Migrationen verifizieren
|
|
|
|
|
6. Worker-Container starten
|
|
|
|
|
7. App-Health verifizieren
|
|
|
|
|
8. Domain-Erreichbarkeit prüfen
|
|
|
|
|
|
|
|
|
|
**Funktioniert auf jeder Coolify-Instanz. Bei mehreren Apps. Bei Erst-Deploy und Redeploy.**
|
|
|
|
|
|
|
|
|
|
### Option B: Docker Compose (lokal / ohne Coolify)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# .env.docker erstellen
|
|
|
|
|
cp .env.docker.example .env.docker
|
|
|
|
|
$EDITOR .env.docker # SECRET_KEY, POSTGRES_PASSWORD, etc. ausfüllen
|
|
|
|
|
|
|
|
|
|
# Starten (alle 4 Container: Postgres, Redis, App, Worker)
|
|
|
|
|
docker compose --env-file .env.docker up --build -d
|
|
|
|
|
|
|
|
|
|
# Health check
|
|
|
|
|
curl http://localhost:8000/api/v1/health
|
|
|
|
|
|
|
|
|
|
# Stoppen
|
|
|
|
|
docker compose down
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Container:**
|
|
|
|
|
- `crm-postgres` — PostgreSQL 16 mit pgvector
|
|
|
|
|
- `crm-redis` — Redis 7
|
|
|
|
|
- `crm-app` — FastAPI API Server
|
|
|
|
|
- `crm-worker` — ARQ Background Worker
|
|
|
|
|
|
|
|
|
|
Alle mit persistenten Volumes. Kein Datenverlust bei Redeploy.
|
|
|
|
|
|
|
|
|
|
## Voraussetzungen
|
|
|
|
|
|
|
|
|
|
- Python 3.12+
|
|
|
|
|
- Docker & Docker Compose (für Option B)
|
|
|
|
|
- Coolify v4+ (für Option A)
|
|
|
|
|
- SSH-Zugang zum Server (für Option A)
|
|
|
|
|
|
|
|
|
|
## Umgebungsvariablen
|
|
|
|
|
|
|
|
|
|
Siehe `.env.example` für alle Variablen. Wichtigste:
|
|
|
|
|
|
|
|
|
|
| Variable | Pflicht | Default | Beschreibung |
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
| `DATABASE_URL` | Ja | — | PostgreSQL Connection String |
|
|
|
|
|
| `REDIS_URL` | Ja | — | Redis Connection String |
|
|
|
|
|
| `SECRET_KEY` | Ja | — | Mindestens 32 Zeichen |
|
|
|
|
|
| `ENVIRONMENT` | Nein | `development` | `production` oder `development` |
|
|
|
|
|
| `SESSION_COOKIE_SECURE` | Nein | `true` | In Production muss `true` |
|
|
|
|
|
| `STORAGE_PATH` | Nein | `/data/storage` | Datei-Upload-Pfad |
|
|
|
|
|
| `STORAGE_BACKEND` | Nein | `local` | `local` oder `s3` |
|
|
|
|
|
|
|
|
|
|
## S3 Storage (optional)
|
|
|
|
|
|
|
|
|
|
Die App unterstützt S3-kompatiblen Storage. Setze:
|
|
|
|
|
```bash
|
|
|
|
|
STORAGE_BACKEND=s3
|
|
|
|
|
S3_ENDPOINT=https://s3.example.com
|
|
|
|
|
S3_BUCKET=leocrm
|
|
|
|
|
S3_ACCESS_KEY=...
|
|
|
|
|
S3_SECRET_KEY=...
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Test- vs. Produktionsumgebung
|
|
|
|
|
|
|
|
|
|
**Test:**
|
|
|
|
|
```bash
|
|
|
|
|
python scripts/deploy.py --environment test
|
|
|
|
|
```
|
|
|
|
|
Eigene Coolify-App, eigene DB, eigene Domain (`crm-test.media-on.de`).
|
|
|
|
|
|
|
|
|
|
**Produktion:**
|
|
|
|
|
```bash
|
|
|
|
|
python scripts/deploy.py --environment production
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
|
|
|
|
**Container nicht healthy:**
|
|
|
|
|
```bash
|
|
|
|
|
docker logs <container-name> --tail 50
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Migration fehlgeschlagen:**
|
|
|
|
|
```bash
|
|
|
|
|
docker exec <container> alembic upgrade head
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**RLS nicht aktiv:**
|
|
|
|
|
```bash
|
|
|
|
|
python scripts/deploy.py --migrate-only
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Worker nicht gestartet:**
|
|
|
|
|
```bash
|
|
|
|
|
python scripts/deploy.py --skip-build # startet Worker automatisch
|
|
|
|
|
```
|
2026-07-26 21:29:37 +02:00
|
|
|
|
|
|
|
|
## Backup & Restore
|
|
|
|
|
|
|
|
|
|
### Backup (PostgreSQL)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Full DB backup (run on the host or via docker exec)
|
|
|
|
|
docker exec crm-postgres pg_dump -U crm_user -Fc crm_db > backup_$(date +%Y%m%d_%H%M%S).dump
|
|
|
|
|
|
|
|
|
|
# Backup mit Custom-Format (komprimiert, parallel restore-fähig)
|
|
|
|
|
docker exec crm-postgres pg_dump -U crm_user -Fc -Z 9 crm_db > backup_$(date +%Y%m%d).dump
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Backup (Redis — Sessions/Queues)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Redis RDB Snapshot
|
|
|
|
|
docker exec crm-redis redis-cli -a "$REDIS_PASSWORD" SAVE
|
|
|
|
|
docker cp crm-redis:/data/dump.rdb redis_backup_$(date +%Y%m%d).rdb
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Backup (File Storage)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Local storage volume
|
|
|
|
|
docker run --rm -v leocrm-fix_storage:/data -v $(pwd):/backup alpine \
|
|
|
|
|
tar czf /backup/storage_$(date +%Y%m%d).tar.gz /data
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Restore (PostgreSQL)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Stop app containers
|
|
|
|
|
docker compose stop crm-app crm-worker
|
|
|
|
|
|
|
|
|
|
# Restore DB
|
|
|
|
|
docker exec -i crm-postgres pg_restore -U crm_user -d crm_db --clean < backup_20260726.dump
|
|
|
|
|
|
|
|
|
|
# Restart app
|
|
|
|
|
docker compose start crm-app crm-worker
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Automatisierte Backups (Cron)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# /etc/cron.d/leocrm-backup
|
|
|
|
|
0 2 * * * root docker exec crm-postgres pg_dump -U crm_user -Fc crm_db > /backups/leocrm_$(date +\%Y\%m\%d).dump
|
|
|
|
|
0 3 * * * root find /backups -name 'leocrm_*.dump' -mtime +30 -delete
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Empfehlung:** Tägliche DB-Backups, 30 Tage Aufbewahrung. Storage-Backup wöchentlich.
|