Files
opencrm/docker-compose.yml
T
duffyduck 70e5190594 docker: DATABASE_URL im entrypoint URL-encoden (Sonderzeichen-Bug auf Prod)
Bug auf Prod-System (frische Installation): MariaDB legte 'opencrm'-User
korrekt an, aber Backend bekam "Access denied for user 'opencrm'@...".

Ursache: docker-compose substituierte ${DB_PASSWORD} naiv in
"mysql://${DB_USER}:${DB_PASSWORD}@db:3306/${DB_NAME}". Wenn das
Passwort Sonderzeichen wie $, !, #, @, :, / enthielt, brach das die
URL-Authority-Syntax → Backend connectete mit kaputtem Passwort.

Fix:
- docker-compose.yml: DATABASE_URL aus environment ENTFERNT.
  Stattdessen DB_HOST=db, DB_PORT=3306, DB_NAME, DB_USER, DB_PASSWORD
  als plain env-vars an den Container.
- backend/docker-entrypoint.sh: baut DATABASE_URL beim Start mit
  encodeURIComponent für User+Passwort (via node -e, kein extra Tool
  wie jq nötig). Funktioniert für beliebige Sonderzeichen.

Live-verifiziert:
- 'secret$1!#with@special' → 'secret%241!%23with%40special' (encoded)
- Backend connectet sauber, Login funktioniert
- entrypoint loggt: "[entrypoint] DATABASE_URL aus DB_*-Komponenten
  gebaut (host=db)"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:25:13 +02:00

111 lines
3.8 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenCRM komplettes Setup: MariaDB + Backend/Frontend + Adminer
# Konfiguration über ./.env (siehe ./.env.example)
#
# Quick-Start (Compose v2):
# cp .env.example .env # Werte anpassen (Secrets rotieren!)
# docker compose up -d # erstes Mal: holt Images, baut Backend, startet alles
# Quick-Start (Compose v1, Legacy):
# docker-compose up -d
#
# Browser:
# http://localhost:${OPENCRM_PORT} # CRM
# http://localhost:${ADMINER_PORT} # DB-UI
#
# Daten liegen alle unter ./data/* Bind-Mounts statt Volumes (auf Wunsch).
#version: '3.8'
services:
db:
image: mariadb:10.11
container_name: opencrm-db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MARIADB_DATABASE: ${DB_NAME}
MARIADB_USER: ${DB_USER}
MARIADB_PASSWORD: ${DB_PASSWORD}
ports:
# Externe Erreichbarkeit für lokale DB-Tools (TablePlus etc.).
# Auf 127.0.0.1 binden kein public exposure.
- "127.0.0.1:${DB_PORT:-3306}:3306"
volumes:
- ${DB_DATA_DIR:-./data/db}:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 20s
interval: 10s
timeout: 5s
retries: 5
opencrm:
build:
context: .
dockerfile: backend/Dockerfile
container_name: opencrm-app
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
# DATABASE_URL wird vom entrypoint.sh aus den DB_*-Komponenten gebaut
# mit encodeURIComponent für Passwörter mit Sonderzeichen ($, !, #, @, :,
# / etc.). KEIN root für die App, sondern der App-User ${DB_USER}, den
# MariaDB beim ersten Start automatisch mit GRANT ALL PRIVILEGES auf
# ${DB_NAME}.* anlegt (über MARIADB_USER/MARIADB_PASSWORD).
DB_HOST: db
DB_PORT: 3306
DB_NAME: ${DB_NAME}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d}
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
NODE_ENV: production
PORT: 3001
LISTEN_ADDR: 0.0.0.0
CORS_ORIGINS: ${CORS_ORIGINS:-}
RUN_SEED: ${RUN_SEED:-false}
ports:
- "${OPENCRM_PORT:-3010}:3001"
volumes:
# Bind-Mounts für persistente Daten unter ./data/
- ${UPLOADS_DIR:-./data/uploads}:/app/uploads
- ${FACTORY_DEFAULTS_DIR:-./data/factory-defaults}:/app/factory-defaults
- ${BACKUPS_DIR:-./data/backups}:/app/prisma/backups
adminer:
image: adminer:latest
container_name: opencrm-adminer
restart: unless-stopped
depends_on:
- db
environment:
ADMINER_DEFAULT_SERVER: db
ADMINER_DESIGN: ${ADMINER_DESIGN:-pepa-linha}
# Adminers offizieller entrypoint linkt nur Designs, deren CSS exakt
# `adminer.css` heißt. Manche Designs (dracula, adminer-dark) haben aber
# `adminer-dark.css`. Wir machen den Symlink generisch: erstes .css im
# gewählten Design wird verlinkt. Danach übergeben wir an den originalen
# entrypoint.sh.
entrypoint:
- /bin/sh
- -c
- >
cd /var/www/html;
if [ -n "$$ADMINER_DESIGN" ] && [ -d "designs/$$ADMINER_DESIGN" ]; then
CSS=$$(ls designs/$$ADMINER_DESIGN/*.css 2>/dev/null | head -1);
if [ -n "$$CSS" ]; then
ln -sf "$$CSS" adminer.css;
touch .adminer-init;
echo "[adminer-bootstrap] Theme aktiv: $$ADMINER_DESIGN -> $$CSS";
else
echo "[adminer-bootstrap] Design '$$ADMINER_DESIGN' enthält kein CSS nutze Default";
fi;
fi;
exec entrypoint.sh docker-php-entrypoint "$$@"
- --
command: ["php", "-S", "[::]:8080", "-t", "/var/www/html"]
ports:
- "127.0.0.1:${ADMINER_PORT:-8090}:8080"