# 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) ---------- # Brauchst du nur, wenn du KEINEN eigenen Reverse-Proxy hast (nginx, Nginx # Proxy Manager, Traefik) und Caddy das SSL übernehmen soll. # # EIN/AUS über diesen Schalter – nichts auskommentieren: # leer -> Caddy AUS, wird nicht einmal angelegt ← Standard # caddy -> Caddy startet bei jedem `docker-compose up -d` mit # Der Schalter wirkt auch bei `down`, `logs` usw. – im Gegensatz zum # Kommandozeilen-Flag `--profile caddy`, das man leicht vergisst. COMPOSE_PROFILES= # leer lassen = Caddy aus # Die folgenden drei Werte werden NUR gebraucht, wenn oben `caddy` steht. # Ohne Caddy kannst du sie ignorieren. 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=, 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=