Der zweite Stack unter docker/ war ein Duplikat aus Februar, das nie mitgepflegt wurde - und genau deshalb schwer zu finden und leicht falsch zu bedienen. Statt ihn zu loeschen (Caddy ist fuer Betreiber ohne eigenen Reverse-Proxy zurecht gewuenscht) ist er jetzt in den Hauptstack integriert: - caddy als optionaler Dienst mit `profiles: ["caddy"]` in docker-compose.yml. Ohne `--profile caddy` wird er nicht einmal angelegt - empirisch geprueft mit einem separaten Testprojekt: `up -d` startete nur den ungeschuetzten Dienst. Der laufende Stack bleibt damit unveraendert. - Caddyfile in den Projektstamm verschoben, proxy-Ziel auf den Dienstnamen `opencrm` angepasst, Zertifikate unter ./data/caddy wie alle anderen Daten. - DOMAIN, CADDY_DIR und CADDY_CONFIG_DIR in die .env.example aufgenommen. - docker/ entfernt (Dockerfile, entrypoint.sh, docker-compose.yml, .env.example, README.md). Das dortige Dockerfile basierte noch auf Alpine - genau die Variante, von der das Projekt wegen Prisma-/TLS-Problemen bewusst auf node:20-slim gewechselt ist. Das gepflegte backend/Dockerfile baut Frontend und Backend ebenso. - README: Abschnitt "Docker (Produktion)" ersetzt durch "Betrieb mit eigenem SSL", inkl. Hinweisen zu Let's-Encrypt-Limits, DNS-Voraussetzung, HTTPS_ENABLED und dem weiterhin offenen App-Port. Projektbaum und .dockerignore nachgezogen. Geprueft: docker-compose config gueltig, caddy validate gueltig, laufende Container unberuehrt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
141 lines
6.8 KiB
Bash
141 lines
6.8 KiB
Bash
# OpenCRM – zentrale Konfiguration
|
||
# ==================================
|
||
# Kopiere diese Datei zu .env und passe die Werte an.
|
||
# Diese .env wird sowohl vom Backend (npm run dev) als auch von Docker
|
||
# Compose verwendet.
|
||
|
||
# ============== PORTS (extern erreichbar auf dem Host) ==============
|
||
OPENCRM_PORT=3010 # Backend + Frontend (alles unter einer URL)
|
||
ADMINER_PORT=8090 # Adminer (Datenbank-UI). 8081 ist häufig schon belegt.
|
||
DB_PORT=3306 # MariaDB extern (für lokale Tools/Dev). 0 = nicht freigeben.
|
||
|
||
# ============== DATEN-PFADE (Bind-Mounts) ==============
|
||
# Relativ zum Projektverzeichnis. Werden zur Laufzeit angelegt.
|
||
DATA_DIR=./data
|
||
DB_DATA_DIR=./data/db
|
||
UPLOADS_DIR=./data/uploads
|
||
FACTORY_DEFAULTS_DIR=./data/factory-defaults
|
||
BACKUPS_DIR=./data/backups
|
||
# Auto-aktualisierter BLZ-/Bankdaten-Datensatz (Bundesbank-Bankleitzahlen)
|
||
BANKDATA_DIR=./data/bankdata
|
||
|
||
# ============== DATENBANK ==============
|
||
# Der App-User (DB_USER) wird beim ersten Start automatisch von MariaDB
|
||
# angelegt (über MARIADB_USER/MARIADB_PASSWORD im docker-compose) – mit
|
||
# GRANT ALL PRIVILEGES auf ${DB_NAME}.*. Damit nutzt das Backend NICHT root.
|
||
# DB_ROOT_PASSWORD ist nur für Adminer / Notfall-Wartung.
|
||
DB_HOST=localhost # Im Container überschreibt docker-compose das auf "db"
|
||
DB_NAME=opencrm
|
||
DB_USER=opencrm
|
||
DB_PASSWORD=change-this-password
|
||
DB_ROOT_PASSWORD=change-this-root-password
|
||
|
||
# Connection-String wird aus den DB_*-Komponenten zusammengebaut (dotenv-expand).
|
||
# Manuell überschreiben nur wenn Sonderfälle (z.B. extra Query-Parameter).
|
||
# Hinweis: für lokales Dev mit MariaDB im Container nutze DB_HOST=localhost,
|
||
# weil docker-compose den DB-Port auf 127.0.0.1:DB_PORT mappt.
|
||
DATABASE_URL=mysql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||
|
||
# ============== SECURITY ==============
|
||
# JWT-Secret: min. 32 Zeichen. Generieren: openssl rand -hex 64
|
||
# Wird sowohl für Access- als auch Refresh-Token verwendet.
|
||
JWT_SECRET=change-this-to-a-very-long-random-secret-please-rotate-before-production
|
||
|
||
# Access-/Refresh-Token-Lifetimes
|
||
# - Access-Token: kurzlebig, lebt nur im Browser-Memory (XSS-Schutz)
|
||
# - Refresh-Token: lang, im httpOnly-Cookie (JS-unzugänglich)
|
||
# Wenn der Access abläuft, holt das Frontend transparent einen neuen über
|
||
# /api/auth/refresh – User merkt nichts. Logout invalidiert beide sofort.
|
||
JWT_EXPIRES_IN=15m
|
||
JWT_REFRESH_EXPIRES_IN=7d
|
||
|
||
# Encryption-Key für Portal-Credentials: GENAU 64 Hex-Zeichen.
|
||
# Generieren: openssl rand -hex 32
|
||
ENCRYPTION_KEY=change-this-to-64-hex-characters-please-rotate-before-production-xx
|
||
|
||
# ---------- Optionaler Reverse-Proxy (Caddy) ----------
|
||
# Nur nötig, wenn du KEINEN eigenen Reverse-Proxy hast und Caddy das SSL
|
||
# übernehmen soll. Starten dann mit: docker-compose --profile caddy up -d
|
||
# Ohne dieses Profil bleibt Caddy aus und ändert nichts am Setup.
|
||
DOMAIN=crm.example.com
|
||
CADDY_DIR=./data/caddy
|
||
CADDY_CONFIG_DIR=./data/caddy-config
|
||
|
||
# ---------- Siegel für das Audit-Log ----------
|
||
# OpenCRM protokolliert, wer wann welche Daten gesehen oder geändert hat – die
|
||
# Beweisspur bei Streit oder Datenschutz-Nachfragen. Dieser Schlüssel versieht
|
||
# jeden neuen Eintrag mit einem Siegel, das sich nur damit erzeugen lässt. Er
|
||
# liegt AUSSERHALB der Datenbank; wer nur die Datenbank in die Hände bekommt,
|
||
# kann damit nichts fälschen, ohne dass es auffliegt.
|
||
#
|
||
# Generieren: openssl rand -hex 32 (pro Umgebung ein eigener Wert)
|
||
#
|
||
# Ohne Wert läuft alles normal weiter, nur eben ungesiegelt – nichts fällt aus.
|
||
# Nachträglich setzen ist jederzeit möglich: bestehende Einträge bleiben gültig,
|
||
# ab dem Neustart werden neue gesiegelt (keine Fehlalarme dadurch).
|
||
#
|
||
# ACHTUNG – einmal gesetzt, nicht wieder entfernen: Einträge, die ohne Schlüssel
|
||
# entstehen, werden beanstandet, sobald er zurück ist (ein ungesiegelter Eintrag
|
||
# inmitten gesiegelter ist von einer Fälschung nicht zu unterscheiden).
|
||
# Schlüssel sichern wie ein Passwort – geht er verloren, sind die damit
|
||
# gesiegelten Einträge dauerhaft nicht mehr prüfbar.
|
||
# Ausführlich erklärt in der README, Abschnitt "Audit-Siegel".
|
||
AUDIT_HMAC_KEY=
|
||
|
||
# Nur beim Schlüsselwechsel füllen: die FRÜHEREN Schlüssel, kommagetrennt und
|
||
# jüngster zuerst. Damit bleiben die bisherigen Einträge prüfbar, während neue
|
||
# schon mit dem neuen Schlüssel gesiegelt werden. Nicht voreilig leeren – sonst
|
||
# werden die alten Einträge als "manipuliert" gemeldet.
|
||
# Beispiel: AUDIT_HMAC_KEY_OLD=<vorheriger>,<davor>
|
||
AUDIT_HMAC_KEY_OLD=
|
||
|
||
# Server
|
||
NODE_ENV=development
|
||
PORT=3001 # Backend-internal Port (Dev: localhost:3001)
|
||
LISTEN_ADDR=0.0.0.0 # In Docker = 0.0.0.0, in Bare-Metal-Production = 127.0.0.1
|
||
|
||
# CORS – nur in Production setzen, wenn Frontend auf separater Domain läuft.
|
||
# Beispiel: CORS_ORIGINS=https://crm.deine-domain.de
|
||
# CORS_ORIGINS=
|
||
|
||
# HTTPS-only-Header (HSTS + upgrade-insecure-requests) – NUR aktivieren, wenn
|
||
# wirklich ein TLS-Proxy (Caddy/Traefik/Nginx) vor OpenCRM steht. Sonst sperrt
|
||
# sich der Browser bei direktem http://ip:port-Zugriff selbst aus
|
||
# (ERR_SSL_PROTOCOL_ERROR auf den Assets).
|
||
HTTPS_ENABLED=false
|
||
|
||
# SSRF-Schutz: private IP-Ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12,
|
||
# 192.168.0.0/16, ::1, fc00::/7, localhost) bei Provider/SMTP-Test-Connection
|
||
# blockieren. Default `false` damit On-Prem-Setups Plesk/Dovecot/Postfix auf
|
||
# 127.0.0.1 oder im internen Netz nutzen können. Für Cloud-Deployments
|
||
# (öffentlich erreichbares Backend) auf `true` setzen, sonst kann ein
|
||
# eingeloggter Admin via /email-providers/test-connection interne Services
|
||
# anpingen. Cloud-Metadata-Endpoints (169.254.169.254 etc.) sind UNABHÄNGIG
|
||
# vom Flag immer geblockt.
|
||
SSRF_BLOCK_PRIVATE_IPS=false
|
||
|
||
# ============== ADMINER (DB-UI) ==============
|
||
# Theme-Auswahl. Verfügbare Designs im offiziellen adminer:latest Image:
|
||
# adminer-dark, brade, bueltge, dracula, esterka, flat, galkaev,
|
||
# haeckel, hever, konya, lavender-light, lucas-sandery, mancave,
|
||
# mvt, nette, ng9, nicu, pappu687, paranoiq, pepa-linha, pokorny,
|
||
# price, rmsoft, rmsoft_blue, rmsoft_blue-dark, win98
|
||
# Empfehlung: dracula (dark) oder adminer-dark – beide modern.
|
||
ADMINER_DESIGN=dracula
|
||
|
||
# ============== SEED ==============
|
||
# Bei leerer DB seedet der Container automatisch (legt admin@admin.com +
|
||
# Stammdaten an) – nichts zu konfigurieren.
|
||
# Nur wenn man eine NICHT-leere DB nochmal forciert seeden will (z.B. nach
|
||
# Reset / Stammdaten-Update), kurz auf 'true' setzen, neu starten, dann
|
||
# wieder zurück.
|
||
RUN_SEED=false
|
||
|
||
# Initial-Passwort für admin@admin.com beim Seed. Mindestens 25 Zeichen,
|
||
# sonst wird der Wert ignoriert und stattdessen ein 28-Zeichen-Zufalls-
|
||
# passwort erzeugt und EINMAL nach stdout geschrieben:
|
||
# docker logs opencrm-app 2>&1 | grep -A 5 "Initial-Passwort"
|
||
# Wer keine Lust auf die Log-Suche hat, setzt hier ein eigenes starkes
|
||
# Passwort vor dem ersten `docker compose up -d`.
|
||
# SEED_ADMIN_PASSWORD=
|