- Remove POSTGRES_COMPOSE, REDIS_COMPOSE templates (unused) - Remove create_service(), create_api_application(), generate_worker_compose() - Remove deploy_worker(), deploy_worker_only(), verify_worker_service() - Remove resolve_worker_uuid() and all worker_uuid references - Remove get_worker_envs(), get_api_envs(), get_postgres_envs(), get_redis_envs() - Remove set_service_envs(), set_application_envs() (dead code) - Remove _extract_deploy_uuid(), _wait_service_healthy() (only used by deploy_worker) - Remove seed_admin_user() (only used by old deploy_full) - Remove DB_HOST, REDIS_HOST, WORKER_UUID, WORKER_NAME config vars - Remove --worker-only CLI arg - Replace old deploy_full() with simple redeploy via /api/v1/deploy - Update run_verification() to remove worker_uuid param - Add KI workflow comment at top of deploy.py - Update DEPLOY.md: single docker-compose stack workflow - Update COOLIFY_SETUP.md: single docker-compose stack, remove 3-resource setup - Update docs/INSTALL.md: automated --initial workflow deploy.py: 1370 → 893 lines (-477 lines, -35%)
6.8 KiB
LeoCRM Deployment
Architektur
LeoCRM läuft als einzelner docker-compose Stack in Coolify. Alle 4 Container
(PostgreSQL, Redis, API, Worker) werden aus der docker-compose.yaml im Git-Repo
gestartet und teilen sich ein Docker-Netzwerk.
┌─────────────────────────────────────────────┐
│ Coolify Application (docker-compose) │
│ ┌──────────┐ ┌──────────┐ │
│ │ postgres │ │ redis │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ ┌────┴─────┐ ┌────┴─────┐ │
│ │ crm_app │ │crm_worker│ │
│ │ (API) │ │ (ARQ) │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────┘
Keine separaten Coolify Services für DB/Redis/Worker. Alles in einem Stack.
Quick Start
Redeploy (bestehende Anwendung)
# Umgebungsvariablen setzen
export COOLIFY_API_TOKEN="dein-token"
export APP_DOMAIN="https://crm.media-on.de"
export COOLIFY_APP_UUID="dx4pqdziu4uj6x9fxs1u5z0x" # optional, wird via APP_NAME gesucht
# Redeploy via Coolify API
python scripts/deploy.py
# Verifikation nur
python scripts/deploy.py --verify-only
Das Script macht automatisch:
- Coolify Application auflösen (via UUID oder Name)
- Deploy via
/api/v1/deploytriggern - Auf Deployment-Erfolg warten
- HTTP Health-Check verifizieren
- Login-Test (optional, wenn LOGIN_EMAIL/LOGIN_PASSWORD gesetzt)
- Alembic-Migration-Head prüfen (via SSH)
- RLS-Tabellen zählen (via SSH)
Initial Deployment (neue Anwendung)
# Alle Umgebungsvariablen setzen
export COOLIFY_API_TOKEN="dein-token"
export APP_DOMAIN="https://crm.media-on.de"
export APP_NAME="leocrm" # Coolify Application Name
export DB_PASSWORD="..."
export REDIS_PASSWORD="..."
export SECRET_KEY="..."
export COOLIFY_PROJECT_UUID="..."
export COOLIFY_SERVER_UUID="..."
export COOLIFY_PRIVATE_KEY_UUID="..."
export COOLIFY_ENVIRONMENT="production" # optional, default: production
# Initial deployment
python scripts/deploy.py --initial
Das Script macht automatisch:
- Coolify Application via
private-deploy-keyerstellen - Build Pack auf
dockercomposesetzen (liest docker-compose.yaml aus Git) - Environment-Variablen setzen (Secrets, Domain, Admin-Credentials)
- Erster Deploy (ohne Domain — Coolify muss docker-compose.yaml lesen)
docker_compose_domainssetzen + Redeploy (mit Traefik-Labels)- Verifikation (HTTP, Login, Alembic, RLS)
Option B: Docker Compose (lokal / ohne Coolify)
# .env.docker erstellen
cp .env.docker.example .env.docker
$EDITOR .env.docker # SECRET_KEY, DB_PASSWORD, REDIS_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:
postgres— PostgreSQL 16 mit pgvectorredis— Redis 7crm_app— FastAPI API Servercrm_worker— ARQ Background Worker
Alle mit persistenten Volumes. Kein Datenverlust bei Redeploy.
Voraussetzungen
- Python 3.12+
httpxPython package- Docker & Docker Compose (für Option B)
- Coolify v4+ (für Option A)
- SSH-Zugang zum Server (für Verifikation, Option A)
Umgebungsvariablen
Siehe .env.example für alle Variablen. Wichtigste:
| Variable | Pflicht | Default | Beschreibung |
|---|---|---|---|
COOLIFY_API_TOKEN |
Ja | — | Coolify API Token |
APP_DOMAIN |
Ja | — | App-Domain (z.B. https://crm.media-on.de) |
COOLIFY_APP_UUID |
Nein | — | Application UUID (auto-resolved via APP_NAME) |
APP_NAME |
Nein | abgeleitet aus APP_DOMAIN | Coolify Application Name |
SSH_KEY |
Nein | /a0/usr/workdir/.ssh/coolify-01-root |
SSH Key für Verifikation |
SERVER_IP |
Nein | 46.225.91.159 |
Server IP für SSH |
LOGIN_EMAIL |
Nein | — | Login-Test Email (optional) |
LOGIN_PASSWORD |
Nein | — | Login-Test Passwort (optional) |
Nur für --initial:
| Variable | Pflicht | Beschreibung |
|---|---|---|
DB_PASSWORD |
Ja | PostgreSQL Passwort |
REDIS_PASSWORD |
Ja | Redis Passwort |
SECRET_KEY |
Ja | Application Secret Key (min. 32 Zeichen) |
COOLIFY_PROJECT_UUID |
Ja | Coolify Project UUID |
COOLIFY_SERVER_UUID |
Ja | Coolify Server UUID |
COOLIFY_PRIVATE_KEY_UUID |
Ja | Coolify Private Deploy Key UUID |
COOLIFY_ENVIRONMENT |
Nein | Coolify Environment (default: production) |
S3 Storage (optional)
Die App unterstützt S3-kompatiblen Storage. Setze:
STORAGE_BACKEND=s3
S3_ENDPOINT=https://s3.example.com
S3_BUCKET=leocrm
S3_ACCESS_KEY=...
S3_SECRET_KEY=...
Mehrere Instanzen
Mehrere LeoCRM-Instanzen auf demselben Coolify-Server:
# Test-Instanz
APP_NAME=leocrm-test APP_DOMAIN=https://crm-test.media-on.de python scripts/deploy.py --initial
# Produktions-Instanz
APP_NAME=leocrm APP_DOMAIN=https://crm.media-on.de python scripts/deploy.py --initial
Jede Instanz hat eigene DB, Redis, Container und Domain.
Troubleshooting
Container nicht healthy:
docker logs <container-name> --tail 50
Migration fehlgeschlagen:
docker exec <container> alembic upgrade head
503 Fehler (Traefik):
- Domain ohne
:443indocker_compose_domainssetzen - Service-Namen mit Unterstrichen in docker-compose.yaml (crm_app, nicht crm-app)
docker-compose.yaml(nicht.yml) als Dateiname
Backup & Restore
Backup (PostgreSQL)
# Full DB backup (run on the host or via docker exec)
docker exec <postgres-container> pg_dump -U crm_user -Fc crm_db > backup_$(date +%Y%m%d_%H%M%S).dump
Backup (Redis — Sessions/Queues)
docker exec <redis-container> redis-cli -a "$REDIS_PASSWORD" SAVE
docker cp <redis-container>:/data/dump.rdb redis_backup_$(date +%Y%m%d).rdb
Restore (PostgreSQL)
# Stop app containers
docker compose stop crm_app crm_worker
# Restore DB
docker exec -i <postgres-container> pg_restore -U crm_user -d crm_db --clean < backup_20260726.dump
# Restart app
docker compose start crm_app crm_worker
Automatisierte Backups (Cron)
# /etc/cron.d/leocrm-backup
0 2 * * * root docker exec <postgres-container> 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.