2026-08-06 01:22:09 +02:00
|
|
|
# Coolify Setup — LeoCRM
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
Production deployment guide for LeoCRM to the Coolify PaaS instance
|
|
|
|
|
at `server.media-on.de`.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## Architektur
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
```
|
2026-08-06 01:22:09 +02:00
|
|
|
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)
|
2026-06-03 23:52:01 +00:00
|
|
|
```
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 1. Voraussetzungen
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
- Coolify server reachable at `https://server.media-on.de`, API token created
|
|
|
|
|
in *Keys & Tokens → API tokens* (Bearer token, scope: `*`).
|
2026-08-06 01:22:09 +02:00
|
|
|
- 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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 2. Initial Deployment (automatisiert)
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
### 2.1 Umgebungsvariablen setzen
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
```bash
|
|
|
|
|
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
|
|
|
|
|
```
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
### 2.2 Deploy starten
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
```bash
|
|
|
|
|
python scripts/deploy.py --initial
|
|
|
|
|
```
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
Das Script führt einen **2-Phase Deploy** durch:
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
2. **Phase 2**: `docker_compose_domains` setzen (für Traefik-Labels), dann
|
|
|
|
|
Redeploy. Jetzt ist die App unter der Domain erreichbar.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
### 2.3 Warum 2-Phase Deploy?
|
2026-07-26 16:26:10 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## 3. Redeploy (bestehende Anwendung)
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
```bash
|
2026-08-06 01:22:09 +02:00
|
|
|
export COOLIFY_API_TOKEN="dein-token"
|
|
|
|
|
export APP_DOMAIN="https://crm.media-on.de"
|
|
|
|
|
export COOLIFY_APP_UUID="dx4pqdziu4uj6x9fxs1u5z0x" # optional
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
python scripts/deploy.py
|
2026-06-03 23:52:01 +00:00
|
|
|
```
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
Triggert `/api/v1/deploy` für die bestehende Coolify Application und wartet auf
|
|
|
|
|
Erfolg. Danach läuft automatisch die Verifikation (HTTP, Login, Alembic, RLS).
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 4. Verifikation
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
```bash
|
|
|
|
|
python scripts/deploy.py --verify-only
|
|
|
|
|
```
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
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)
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 5. Wichtige Hinweise
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
### 5.1 Service-Namen mit Unterstrichen
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
In `docker-compose.yaml` müssen Service-Namen **Unterstriche** verwenden:
|
|
|
|
|
`crm_app`, `crm_worker` — nicht `crm-app`, `crm-worker`.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
Coolify konvertiert Bindestriche zu Unterstrichen in `docker_compose_domains`.
|
|
|
|
|
Bei Bindestrichen in der Compose-Datei gibt es keinen Match → keine
|
|
|
|
|
Traefik-Labels → 503 Fehler.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
### 5.2 docker-compose.yaml (nicht .yml)
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
Coolify sucht nach `docker-compose.yaml` (mit `.yaml`). Eine Datei namens
|
|
|
|
|
`docker-compose.yml` wird nicht gefunden.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
### 5.3 Domain ohne :443
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
### 5.4 Kein connect_to_docker_network
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 6. Mehrere Instanzen
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
```bash
|
2026-08-06 01:22:09 +02:00
|
|
|
# Test-Instanz
|
|
|
|
|
APP_NAME=leocrm-test APP_DOMAIN=https://crm-test.media-on.de \
|
|
|
|
|
python scripts/deploy.py --initial
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
# Produktions-Instanz
|
|
|
|
|
APP_NAME=leocrm APP_DOMAIN=https://crm.media-on.de \
|
|
|
|
|
python scripts/deploy.py --initial
|
|
|
|
|
```
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
Jede Instanz hat eigene DB, Redis, Container und Domain. Alle Parameter werden
|
|
|
|
|
aus `APP_NAME` und `APP_DOMAIN` abgeleitet.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 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.
|
2026-06-03 23:52:01 +00:00
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 8. Healthcheck
|
2026-06-03 23:52:01 +00:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
In **Coolify → Application → Advanced → Healthcheck**:
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
- **Healthcheck path**: `/api/v1/health`
|
|
|
|
|
- **Healthcheck method**: `GET`
|
|
|
|
|
- **Healthcheck interval**: `30s`
|
|
|
|
|
- **Healthcheck timeout**: `10s`
|
|
|
|
|
- **Healthcheck retries**: `3`
|
|
|
|
|
- **Healthcheck start period**: `15s`
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
---
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 9. Going forward — Redeploys
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
- **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.
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
---
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 10. Troubleshooting
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
**503 Fehler (Traefik):**
|
|
|
|
|
- Domain ohne `:443` in `docker_compose_domains`
|
|
|
|
|
- Service-Namen mit Unterstrichen in docker-compose.yaml
|
|
|
|
|
- `docker-compose.yaml` (nicht `.yml`)
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
**Container können sich nicht erreichen (DNS):**
|
|
|
|
|
- Alles in einem docker-compose Stack (nicht separate Coolify Services)
|
|
|
|
|
- Kein `connect_to_docker_network` setzen
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
**"Docker Compose file not found":**
|
|
|
|
|
- Datei heißt `docker-compose.yaml` (nicht `.yml`)
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
**Migration fehlgeschlagen:**
|
|
|
|
|
```bash
|
|
|
|
|
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
|
|
|
|
|
```
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
---
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
## 11. Referenzen
|
2026-07-25 21:03:46 +02:00
|
|
|
|
2026-08-06 01:22:09 +02:00
|
|
|
- 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`
|