Files
leocrm/COOLIFY_SETUP.md
T

7.2 KiB

Coolify Setup — LeoCRM

Production deployment guide for LeoCRM to the Coolify PaaS instance at server.media-on.de.

Architektur

LeoCRM läuft als einzelner docker-compose Stack in einer Coolify Application. Coolify liest die docker-compose.yaml aus dem Git-Repo und startet alle 4 Container (postgres, redis, crm_app, crm_worker) in einem gemeinsamen Stack.

Coolify Application (build_pack=dockercompose)
├── postgres    (pgvector/pgvector:pg16)
├── redis       (redis:7-alpine)
├── crm_app     (FastAPI API Server, Port 8000)
└── crm_worker  (ARQ Background Worker)

Alle Container teilen sich ein Docker-Netzwerk. Service-Namen funktionieren als DNS-Namen (z.B. postgres, redis, crm_app, crm_worker).

Keine separaten Coolify Services für DB/Redis/Worker. Das funktioniert nicht, weil Coolify jedem Service ein eigenes Netzwerk gibt und die Container sich nicht per DNS erreichen können.


1. Voraussetzungen

  • Coolify server reachable at https://server.media-on.de, API token created in Keys & Tokens → API tokens (Bearer token, scope: *).
  • DNS A record for die App-Domain (z.B. crm.media-on.de) zeigt auf die öffentliche IP des Coolify-Servers.
  • LeoCRM source code in Forgejo repository: https://forgejo.media-on.de/Leopoldadmin/leocrm.git (branch main).
  • Ein Private Deploy Key in Coolify hinterlegt (für Git-Zugriff).
  • Python 3.12+ mit httpx für das deploy script.

2. Initial Deployment (automatisiert)

2.1 Umgebungsvariablen setzen

export COOLIFY_API_TOKEN="dein-token"
export APP_DOMAIN="https://crm.media-on.de"
export APP_NAME="leocrm"
export DB_PASSWORD="<sicheres-passwort>"
export REDIS_PASSWORD="<sicheres-passwort>"
export SECRET_KEY="<mindestens-32-zeichen>"
export COOLIFY_PROJECT_UUID="<project-uuid>"
export COOLIFY_SERVER_UUID="<server-uuid>"
export COOLIFY_PRIVATE_KEY_UUID="<private-key-uuid>"
export COOLIFY_ENVIRONMENT="production"  # optional
export ADMIN_EMAIL="admin@media-on.de"    # optional
export ADMIN_PASSWORD="Admin123!"         # optional

2.2 Deploy starten

python scripts/deploy.py --initial

Das Script führt einen 2-Phase Deploy durch:

  1. Phase 1: Application via private-deploy-key erstellen, build_pack auf dockercompose setzen, ENV-Variablen setzen, erster Deploy ohne Domain. Coolify liest docker-compose.yaml aus dem Git-Repo und baut alle Container.

  2. Phase 2: docker_compose_domains setzen (für Traefik-Labels), dann Redeploy. Jetzt ist die App unter der Domain erreichbar.

2.3 Warum 2-Phase Deploy?

Coolify muss zuerst die docker-compose.yaml aus dem Git-Repo lesen, um die Service-Namen zu kennen. Erst dann kann docker_compose_domains korrekt zugeordnet werden. Ein Deploy ohne vorherigen Read der Compose-Datei führt zu fehlenden Traefik-Labels → 503 Fehler.


3. Redeploy (bestehende Anwendung)

export COOLIFY_API_TOKEN="dein-token"
export APP_DOMAIN="https://crm.media-on.de"
export COOLIFY_APP_UUID="xf7smknlger3hvkrsb910tui"  # optional

python scripts/deploy.py

Triggert /api/v1/deploy für die bestehende Coolify Application und wartet auf Erfolg. Danach läuft automatisch die Verifikation (HTTP, Login, Alembic, RLS).


4. Verifikation

python scripts/deploy.py --verify-only

Prüft:

  • HTTP Health (/api/v1/health)
  • Login (optional, wenn LOGIN_EMAIL/LOGIN_PASSWORD gesetzt)
  • Alembic Migration Head (via SSH in den postgres Container)
  • RLS-Tabellen-Anzahl (via SSH)

5. Wichtige Hinweise

5.1 Service-Namen mit Unterstrichen

In docker-compose.yaml müssen Service-Namen Unterstriche verwenden: crm_app, crm_worker — nicht crm-app, crm-worker.

Coolify konvertiert Bindestriche zu Unterstrichen in docker_compose_domains. Bei Bindestrichen in der Compose-Datei gibt es keinen Match → keine Traefik-Labels → 503 Fehler.

5.2 docker-compose.yaml (nicht .yml)

Coolify sucht nach docker-compose.yaml (mit .yaml). Eine Datei namens docker-compose.yml wird nicht gefunden.

5.3 Domain ohne :443

In docker_compose_domains darf die Domain kein :443 am Ende haben:

✅  https://crm.media-on.de
❌  https://crm.media-on.de:443

Das :443 führt zu leeren Host() Traefik-Labels.

5.4 Kein connect_to_docker_network

Innerhalb eines docker-compose Stacks kümmert sich Coolify selbst um das Netzwerk. connect_to_docker_network=True ist nicht nötig und sollte nicht gesetzt werden.


6. Mehrere Instanzen

# 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. Alle Parameter werden aus APP_NAME und APP_DOMAIN abgeleitet.


7. Environment-Variablen in Coolify

Das --initial Script setzt automatisch folgende ENV-Variablen in Coolify:

Key Wert Quelle
POSTGRES_USER crm_user Default
POSTGRES_DB crm_db Default
DB_PASSWORD * ENV
REDIS_PASSWORD * ENV
SECRET_KEY * ENV
ENVIRONMENT production Default
LOG_LEVEL INFO Default
SESSION_COOKIE_SECURE true Default
STORAGE_PATH /data/storage Default
CORS_ORIGINS APP_DOMAIN ENV
FRONTEND_URL APP_DOMAIN ENV
APP_DOMAIN APP_DOMAIN ENV
ADMIN_EMAIL admin@media-on.de ENV (optional)
ADMIN_PASSWORD Admin123! ENV (optional)

Die docker-compose.yaml verwendet ${VARIABLE} Syntax — Coolify substituiert aus diesen ENV-Variablen.


8. Healthcheck

In Coolify → Application → Advanced → Healthcheck:

  • Healthcheck path: /api/v1/health
  • Healthcheck method: GET
  • Healthcheck interval: 30s
  • Healthcheck timeout: 10s
  • Healthcheck retries: 3
  • Healthcheck start period: 15s

9. Going forward — Redeploys

  • Code change → push to main auf Forgejo → python scripts/deploy.py (oder Coolify UI → Deployments → Deploy).
  • Environment variable change → Coolify UI (oder API PATCH .../envs/bulk) → Deploy (Coolify startet nicht automatisch bei ENV-Änderung neu).
  • Domain change → API (PATCH /api/v1/applications/{uuid} mit docker_compose_domains) — reproduzierbar, UI als Fallback.

10. Troubleshooting

503 Fehler (Traefik):

  • Domain ohne :443 in docker_compose_domains
  • Service-Namen mit Unterstrichen in docker-compose.yaml
  • docker-compose.yaml (nicht .yml)

Container können sich nicht erreichen (DNS):

  • Alles in einem docker-compose Stack (nicht separate Coolify Services)
  • Kein connect_to_docker_network setzen

"Docker Compose file not found":

  • Datei heißt docker-compose.yaml (nicht .yml)

Migration fehlgeschlagen:

docker exec <postgres-container> psql -U crm_user -d crm_db -c "SELECT version_num FROM alembic_version"
docker exec <api-container> alembic upgrade head

11. Referenzen

  • Coolify v4 API — /a0/usr/plugins/coolify_control/help/coolify-control/help.md
  • App architecture — architecture.md
  • Deploy script — scripts/deploy.py
  • Install guide — docs/INSTALL.md