DocsSelf-Hosting › Betrieb

Self-Hosting-Betrieb (Updates, Backup, Env, Monitoring)

Dieses Handbuch richtet sich an Founder, die The-Y CRM selbst hosten. Es deckt den laufenden Betrieb ab: den Docker-Stack, Updates, Backup & Restore, die wichtigsten Umgebungsvariablen, Reverse-Proxy/TLS, Monitoring und die Lizenz. Für Erstinstallation & Server-Größe siehe Installation und Server-Anforderungen.

Zielgruppe: Self-Hosting (Paid/Founder) · Docker Compose · Linux-Grundkenntnisse hilfreich

Der Stack im Überblick

The-Y läuft als Docker-Compose-Stack. Die Dienste:

DienstZweck
appdie Web-App (Next.js) — bindet intern auf Port 3000
workerHintergrund-Jobs (E-Mail-Abruf, Erinnerungen, Sweeps, Automatisierungs-Scheduler)
postgresDatenbank (alle Mandantendaten)
redisJob-Queue (BullMQ)
minioDatei-/Medien-Speicher (Anhänge, Aufnahmen) — S3-kompatibel
caddyReverse-Proxy mit automatischem HTTPS
watchtoweroptionaler Auto-Updater (nächtlicher Image-Pull)
optional: asterisk, coturn, piperTelefonanlage, TURN (WebRTC), neuronale Sprachansagen

Updates

Zwei Wege — beide ziehen die neuen Images von Docker Hub:

cd ~/the-y-crm
docker compose pull app worker
docker compose up -d app worker
Datenbank-Migrationen laufen beim App-Start automatisch (der Container führt migrate vor start aus) — kein separater Schritt nötig.

Backup & Restore

Sichere regelmäßig drei Dinge: die Postgres-Datenbank, das MinIO-Volume (Dateien/Medien) und deine .env (enthält u. a. den Verschlüsselungsschlüssel — ohne ihn sind verschlüsselte Secrets verloren!).

Backup

# 1) Datenbank-Dump
cd ~/the-y-crm
docker compose exec -T postgres pg_dump -U crm crm | gzip > db-$(date +%F).sql.gz
# 2) MinIO-Volume (Dateien/Medien)
docker run --rm -v the-y-crm_minio-data:/data -v "$PWD":/backup alpine \
  tar czf /backup/minio-$(date +%F).tgz -C /data .
# 3) .env sichern (enthält APP_ENCRYPTION_KEY!)
cp .env env-$(date +%F).bak

Lege die drei Dateien an einen getrennten Ort (anderer Server/Storage). Automatisiere das per Cron.

Restore

# DB zurückspielen
gunzip -c db-JJJJ-MM-TT.sql.gz | docker compose exec -T postgres psql -U crm crm
# MinIO-Volume zurückspielen (Stack vorher stoppen)
docker run --rm -v the-y-crm_minio-data:/data -v "$PWD":/backup alpine \
  sh -c "rm -rf /data/* && tar xzf /backup/minio-JJJJ-MM-TT.tgz -C /data"
Zusätzlich gibt es im Produkt einen Snapshot-Export/Import je Mandant (Einstellungen → Sicherung) — praktisch für Umzüge und als anwendungsnahe Sicherung. Die DB+MinIO-Sicherung oben ist die vollständige Infrastruktur-Sicherung.
Der Verschlüsselungsschlüssel ist kritisch. Postfach-/SIP-/API-/Kanal-Tokens werden mit APP_ENCRYPTION_KEY (AES-256) verschlüsselt gespeichert. Ändert oder verlierst du diesen Schlüssel, sind alle bestehenden Secrets nicht mehr entschlüsselbar. Setze ihn einmal fest und sichere ihn (Teil deiner .env-Sicherung).

Umgebungsvariablen (Referenz)

Die wichtigsten Werte in deiner .env (Vorlage: .env.self-host.example). Kritische fett.

VariableZweck
APP_ENCRYPTION_KEYFester 32-Byte-Hex-Schlüssel (openssl rand -hex 32) für die Feld-Verschlüsselung. Nie ändern.
DATABASE_URLPostgres-Superuser-Verbindung (Migration/Skripte)
APP_DATABASE_URLApp-Verbindung als Nicht-Superuser crm_app (erzwingt Row-Level-Security = Mandantentrennung)
BASE_DOMAINdeine Domain (z. B. crm.deinefirma.at) — u. a. fürs Softphone (WSS)
TENANT_MODEself-host: single (ein Mandant, kein Fremd-Signup)
LICENSE_KEYdein Founder-/Lizenzschlüssel; wird online validiert (14 Tage Offline-Toleranz)
CONTROL_PLANE_URLLizenz-Prüf-Endpunkt (Standard: crm.the-y.at)
S3_ENDPOINT / S3_BUCKETMinIO-Anbindung (minio:9000 / crm-media)
MINIO_ROOT_USER / _PASSWORDMinIO-Zugangsdaten (generieren)
PLATFORM_SMTP_* / PLATFORM_MAIL_FROMoptionaler System-Mailer (Passwort-Reset/Einladungen) ohne eigenes Postfach
CRM_IMAGE/_WORKER_IMAGE/CRM_TAGDocker-Hub-Images + Tag (Standard :latest)
Telefonie: AMI_SECRET u. a.nur bei aktivierter Telefonanlage

Reverse-Proxy & TLS

Das Bundle bringt Caddy mit automatischem HTTPS mit (Let's Encrypt) — du zeigst nur deine Domain per DNS auf den Server. Betreibst du bereits nginx/Apache davor, proxie stattdessen auf die App (intern Port 3000) und terminiere TLS dort. Achte auf durchgereichte WebSocket-Verbindungen (Softphone/Realtime).

Monitoring & Health

Der Endpunkt /api/public/health liefert einen einfachen Gesundheits-Status (HTTP 200 = gesund). Hänge ihn an dein Monitoring (Uptime-Check). Container-Status prüfst du mit docker compose ps, Logs mit docker compose logs -f app worker.

Lizenz

Der LICENSE_KEY wird regelmäßig online gegen die Control-Plane validiert; bei Ausfall gilt eine 14-Tage-Offline-Toleranz. Ist die Lizenz ungültig/abgelaufen, geht die Instanz in einen schonenden Nur-Lese-Zustand (kein harter Lockout, keine Datenlöschung). Der Funktionsumfang ist identisch zur gehosteten Version.

Fehlerbehebung

Nach einem Neuaufsetzen sind Postfach/WhatsApp/Telefonie „kaputt"

Fast immer hat sich der APP_ENCRYPTION_KEY geändert (z. B. neu generiert), wodurch bestehende verschlüsselte Secrets nicht mehr lesbar sind. Stelle den ursprünglichen Schlüssel aus deiner .env-Sicherung wieder her. Ist er endgültig weg, müssen die externen Secrets (Tokens/Passwörter) neu eingegeben werden.

Mails gehen nicht raus (Timeout)

Viele Cloud-Anbieter (Hetzner, netcup, DigitalOcean, AWS/GCP/Azure) blockieren ausgehende SMTP-Ports (25/465/587) standardmäßig als Spam-Schutz. Lass die Ports beim Anbieter freischalten (Support-Ticket) oder nutze einen HTTP-API-Mailversand. Details: Server-Anforderungen §5b.

Instanz ist im Nur-Lese-Modus

Die Lizenzprüfung schlug fehl (ungültiger/abgelaufener Key oder länger als 14 Tage keine erfolgreiche Online-Prüfung). Prüfe LICENSE_KEY und die Erreichbarkeit der CONTROL_PLANE_URL.

Ein Container startet nicht

docker compose logs app zeigt die Ursache. Häufig: falsche DB-Zugangsdaten, fehlender APP_ENCRYPTION_KEY oder ein belegter Port. Nach .env-Änderungen docker compose up -d --force-recreate app worker.

Weiter geht's