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(branchmain). - Ein Private Deploy Key in Coolify hinterlegt (für Git-Zugriff).
- Python 3.12+ mit
httpxfü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:
-
Phase 1: Application via
private-deploy-keyerstellen, build_pack aufdockercomposesetzen, ENV-Variablen setzen, erster Deploy ohne Domain. Coolify liestdocker-compose.yamlaus dem Git-Repo und baut alle Container. -
Phase 2:
docker_compose_domainssetzen (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
mainauf 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}mitdocker_compose_domains) — reproduzierbar, UI als Fallback.
10. Troubleshooting
503 Fehler (Traefik):
- Domain ohne
:443indocker_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_networksetzen
"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