Der Stack bleibt bewusst erhalten: Er richtet sich an Betreiber OHNE eigenen Reverse-Proxy, weil Caddy das Zertifikat selbst holt und erneuert. Er war allerdings seit Februar stehengeblieben und reichte zehn Variablen nicht an den Container durch - teils sicherheitsrelevant. Behoben: - HTTPS_ENABLED ergaenzt (Default true, Caddy terminiert TLS). Fehlte bisher komplett, dadurch waere der Refresh-Cookie OHNE Secure-Attribut gesetzt worden und trust proxy falsch gewesen. - JWT_EXPIRES_IN Default von 7d auf 15m korrigiert - der Wert galt dem ACCESS-Token und stammte aus der Zeit vor dem Access-/Refresh-Pattern. Ein Access-Token mit einer Woche Lebensdauer im Browser-Speicher macht das XSS-Fenster unnoetig gross. - JWT_REFRESH_EXPIRES_IN, CORS_ORIGINS, LISTEN_ADDR, SSRF_BLOCK_PRIVATE_IPS ergaenzt. JWT_REFRESH_EXPIRES_IN stand bereits in docker/.env.example, wurde aber nie durchgereicht - dieselbe Fehlerklasse wie beim Audit-Siegel. - Caddyfile: gzip fuer /api/* deaktiviert (BREACH, CVE-2013-3587). Die Konfiguration komprimierte bisher alles, obwohl die README das fuer die API ausdruecklich ausschliesst. Statische Assets bleiben komprimiert. Mit `caddy validate` geprueft. - docker/.env.example um die neuen Variablen erweitert, dazu ein Hinweis auf Sonderzeichen im DB-Passwort (dieser Stack setzt die DATABASE_URL direkt zusammen, anders als der Entrypoint im Projektstamm). - README benennt jetzt, wann welcher Stack der richtige ist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
108 lines
3.4 KiB
YAML
108 lines
3.4 KiB
YAML
version: '3.8'
|
||
|
||
services:
|
||
# ===================================
|
||
# MariaDB Database
|
||
# ===================================
|
||
db:
|
||
image: mariadb:10.11
|
||
container_name: opencrm-db
|
||
restart: unless-stopped
|
||
environment:
|
||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootpassword}
|
||
MYSQL_DATABASE: ${DB_NAME:-opencrm}
|
||
MYSQL_USER: ${DB_USER:-opencrm}
|
||
MYSQL_PASSWORD: ${DB_PASSWORD:-opencrm123}
|
||
volumes:
|
||
- mariadb_data:/var/lib/mysql
|
||
networks:
|
||
- opencrm-network
|
||
healthcheck:
|
||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||
start_period: 10s
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 3
|
||
|
||
# ===================================
|
||
# OpenCRM Application
|
||
# ===================================
|
||
app:
|
||
build:
|
||
context: ..
|
||
dockerfile: docker/Dockerfile
|
||
container_name: opencrm-app
|
||
restart: unless-stopped
|
||
environment:
|
||
NODE_ENV: production
|
||
PORT: 3001
|
||
DATABASE_URL: mysql://${DB_USER:-opencrm}:${DB_PASSWORD:-opencrm123}@db:3306/${DB_NAME:-opencrm}
|
||
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}
|
||
# Access-Token kurzlebig (lebt nur im Browser-Speicher → XSS-Fenster
|
||
# klein halten), Refresh-Token lang im httpOnly-Cookie.
|
||
# Frueher stand hier 7d fuer den ACCESS-Token – das war ein Ueberbleibsel
|
||
# aus der Zeit vor dem Access-/Refresh-Pattern.
|
||
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-15m}
|
||
JWT_REFRESH_EXPIRES_IN: ${JWT_REFRESH_EXPIRES_IN:-7d}
|
||
ENCRYPTION_KEY: ${ENCRYPTION_KEY:?ENCRYPTION_KEY is required}
|
||
# Caddy terminiert TLS und steht als EIN Proxy davor. Das Flag setzt das
|
||
# Secure-Attribut am Refresh-Cookie, trust proxy = 1 Hop und
|
||
# upgrade-insecure-requests in der CSP. Nur auf false setzen, wenn der
|
||
# Stack bewusst ohne TLS laeuft (reiner Test ueber http://).
|
||
HTTPS_ENABLED: ${HTTPS_ENABLED:-true}
|
||
# Nur noetig, wenn das Frontend unter einer anderen Origin laeuft.
|
||
CORS_ORIGINS: ${CORS_ORIGINS:-}
|
||
# In der Container-Umgebung muss der Dienst fuer Caddy erreichbar sein.
|
||
LISTEN_ADDR: ${LISTEN_ADDR:-0.0.0.0}
|
||
# Cloud-Deploy: private IP-Ranges fuer Provider-/SMTP-Tests blocken.
|
||
SSRF_BLOCK_PRIVATE_IPS: ${SSRF_BLOCK_PRIVATE_IPS:-false}
|
||
# Siegel für das Audit-Log (optional, fail-safe ohne Wert)
|
||
AUDIT_HMAC_KEY: ${AUDIT_HMAC_KEY:-}
|
||
AUDIT_HMAC_KEY_OLD: ${AUDIT_HMAC_KEY_OLD:-}
|
||
RUN_SEED: ${RUN_SEED:-false}
|
||
volumes:
|
||
- uploads_data:/app/uploads
|
||
- backups_data:/app/backups
|
||
networks:
|
||
- opencrm-network
|
||
depends_on:
|
||
db:
|
||
condition: service_healthy
|
||
healthcheck:
|
||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/api/health"]
|
||
start_period: 60s
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
|
||
# ===================================
|
||
# Caddy Reverse Proxy (with auto SSL)
|
||
# ===================================
|
||
caddy:
|
||
image: caddy:2-alpine
|
||
container_name: opencrm-caddy
|
||
restart: unless-stopped
|
||
ports:
|
||
- "80:80"
|
||
- "443:443"
|
||
volumes:
|
||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||
- caddy_data:/data
|
||
- caddy_config:/config
|
||
networks:
|
||
- opencrm-network
|
||
depends_on:
|
||
app:
|
||
condition: service_healthy
|
||
|
||
networks:
|
||
opencrm-network:
|
||
driver: bridge
|
||
|
||
volumes:
|
||
mariadb_data:
|
||
uploads_data:
|
||
backups_data:
|
||
caddy_data:
|
||
caddy_config:
|