Nur noch eine docker-compose.yml und eine .env
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>
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@ backend/dist
|
||||
.vscode
|
||||
.idea
|
||||
*.md
|
||||
!docker/README.md
|
||||
|
||||
|
||||
# Environment files (use Docker environment instead)
|
||||
.env
|
||||
|
||||
@@ -53,6 +53,14 @@ JWT_REFRESH_EXPIRES_IN=7d
|
||||
# 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
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# OpenCRM Caddyfile
|
||||
# ===================
|
||||
# Replace {$DOMAIN} with your actual domain or use environment variable
|
||||
# For local development without SSL, use localhost:80
|
||||
# Wird NUR gebraucht, wenn du den optionalen Caddy-Dienst startest:
|
||||
# docker-compose --profile caddy up -d
|
||||
# Caddy holt und erneuert dann das SSL-Zertifikat automatisch fuer ${DOMAIN}.
|
||||
# Betreibst du bereits einen eigenen Reverse-Proxy (nginx, NPM, Traefik),
|
||||
# brauchst du diese Datei nicht - dann laeuft alles ueber deinen Proxy.
|
||||
|
||||
{$DOMAIN:localhost} {
|
||||
# Reverse proxy to OpenCRM app
|
||||
reverse_proxy app:3001
|
||||
reverse_proxy opencrm:3001
|
||||
|
||||
# Logging
|
||||
log {
|
||||
@@ -341,9 +341,8 @@ openssl rand -hex 32
|
||||
|
||||
| Betrieb | Datei |
|
||||
|---|---|
|
||||
| **Docker** (Standard, `docker-compose.yml` im Projektstamm) | **`.env` im Projektstamm** |
|
||||
| **Docker** (Standard) | **`.env` im Projektstamm** |
|
||||
| Backend direkt, ohne Container (Entwicklung) | `backend/.env` |
|
||||
| Alternativer Caddy-Stack unter `docker/` | `docker/.env` |
|
||||
|
||||
Beim Docker-Betrieb reicht der Eintrag in der Stamm-`.env` – `docker-compose.yml`
|
||||
reicht die Variable an den Container weiter. Ein Eintrag in `backend/.env` wirkt
|
||||
@@ -817,48 +816,44 @@ docker-compose down -v # Container stoppen + Daten löschen
|
||||
docker-compose logs -f # Logs anzeigen
|
||||
```
|
||||
|
||||
### Docker (Produktion)
|
||||
### Betrieb mit eigenem SSL (optionaler Caddy-Dienst)
|
||||
|
||||
Im `docker/` Verzeichnis liegt ein komplettes Produktions-Setup:
|
||||
Es gibt **eine** `docker-compose.yml` und **eine** `.env` im Projektstamm.
|
||||
Standardmässig bringt der Stack **keinen** Reverse-Proxy mit – die Annahme ist,
|
||||
dass du bereits einen hast (nginx, Nginx Proxy Manager, Traefik) und OpenCRM
|
||||
dahinter hängst.
|
||||
|
||||
Hast du **keinen**, kannst du Caddy als optionalen Dienst dazuschalten. Er holt
|
||||
und erneuert das SSL-Zertifikat automatisch:
|
||||
|
||||
```bash
|
||||
cd docker
|
||||
# In der .env die Domain setzen
|
||||
DOMAIN=crm.example.de
|
||||
HTTPS_ENABLED=true
|
||||
|
||||
# Image bauen
|
||||
docker-compose build
|
||||
|
||||
# Container starten
|
||||
docker-compose up -d
|
||||
|
||||
# Logs anzeigen
|
||||
docker-compose logs -f app
|
||||
# Mit Caddy starten (Ports 80 + 443 müssen frei sein)
|
||||
docker-compose --profile caddy up -d
|
||||
```
|
||||
|
||||
**Komponenten:**
|
||||
- **MariaDB 10.11**: Datenbank
|
||||
- **App**: Backend + Frontend in einem Container
|
||||
- **Caddy**: Reverse-Proxy mit automatischem SSL
|
||||
Ohne `--profile caddy` bleibt Caddy aus und nichts ändert sich – der Dienst
|
||||
wird dann gar nicht erst angelegt.
|
||||
|
||||
> **Wann dieser Stack?** Wenn du **keinen** eigenen Reverse-Proxy betreibst –
|
||||
> Caddy holt und erneuert das SSL-Zertifikat hier selbst. Hast du bereits einen
|
||||
> Proxy davor (nginx, Nginx Proxy Manager, Traefik), nimm den Stack im
|
||||
> Projektstamm; er bringt bewusst keinen eigenen Proxy mit.
|
||||
**Was dabei zu beachten ist:**
|
||||
|
||||
**Umgebungsvariablen (`docker/.env`):** – vollständige Vorlage mit Erklärungen
|
||||
in `docker/.env.example`
|
||||
- Die Zertifikate liegen unter `./data/caddy`. Diesen Ordner **nicht löschen**,
|
||||
sonst werden bei jedem Start neue Zertifikate angefordert und du läufst in
|
||||
die Mengenbegrenzung von Let's Encrypt.
|
||||
- Die Domain muss vorher per DNS auf den Server zeigen, sonst schlägt die
|
||||
Zertifikatsausstellung fehl.
|
||||
- `HTTPS_ENABLED=true` setzen – das aktiviert das `Secure`-Attribut am
|
||||
Refresh-Cookie und die korrekte Proxy-Erkennung.
|
||||
- Der direkte App-Port (`OPENCRM_PORT`, Standard 3010) bleibt weiterhin offen.
|
||||
Wenn nur Caddy von aussen erreichbar sein soll, schliesse ihn per Firewall
|
||||
oder setze ihn in der `.env` auf einen Wert, den du nicht freigibst.
|
||||
|
||||
```env
|
||||
DB_ROOT_PASSWORD=sicheres-root-passwort
|
||||
DB_NAME=opencrm
|
||||
DB_USER=opencrm
|
||||
DB_PASSWORD=sicheres-passwort
|
||||
JWT_SECRET=sehr-langer-zufaelliger-string
|
||||
ENCRYPTION_KEY=64-zeichen-hex-string
|
||||
DOMAIN=crm.example.com
|
||||
HTTPS_ENABLED=true # Caddy terminiert TLS → Secure-Cookies an
|
||||
AUDIT_HMAC_KEY= # Siegel fürs Audit-Log, siehe oben
|
||||
RUN_SEED=true # Nur beim ersten Start
|
||||
```
|
||||
Die Konfiguration liegt in der `Caddyfile` im Projektstamm. Sie liefert
|
||||
Sicherheits-Header mit und komprimiert bewusst **nicht** die API-Antworten
|
||||
(BREACH-Schutz, siehe Abschnitt zum Reverse-Proxy oben).
|
||||
|
||||
## Projektstruktur
|
||||
|
||||
@@ -910,7 +905,7 @@ opencrm/
|
||||
│ │ ├── types/ # TypeScript-Typen
|
||||
│ │ └── App.tsx # Haupt-Komponente
|
||||
│ └── package.json
|
||||
├── docker/ # Docker-Deployment
|
||||
├── Caddyfile # Optionaler Reverse-Proxy (nur mit --profile caddy)
|
||||
│ ├── Dockerfile # Multi-Stage Build
|
||||
│ ├── docker-compose.yml # Produktion (MariaDB, App, Caddy)
|
||||
│ ├── Caddyfile # Reverse-Proxy mit SSL
|
||||
|
||||
@@ -90,6 +90,30 @@ services:
|
||||
# Auto-aktualisierter BLZ-/Bankdaten-Datensatz (Bundesbank-Bankleitzahlen)
|
||||
- ${BANKDATA_DIR:-./data/bankdata}:/app/bankdata
|
||||
|
||||
# Optionaler Reverse-Proxy mit automatischem SSL – nur fuer Betreiber OHNE
|
||||
# eigenen Proxy. Startet NICHT mit `docker-compose up -d`, sondern nur mit:
|
||||
# docker-compose --profile caddy up -d
|
||||
# Wer nginx / Nginx Proxy Manager / Traefik davor hat, laesst das weg.
|
||||
caddy:
|
||||
image: caddy:2-alpine
|
||||
container_name: opencrm-caddy
|
||||
restart: unless-stopped
|
||||
profiles: ["caddy"]
|
||||
depends_on:
|
||||
- opencrm
|
||||
environment:
|
||||
DOMAIN: ${DOMAIN:-localhost}
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
# Zertifikate liegen wie alle Daten unter ./data/ – nicht loeschen,
|
||||
# sonst werden bei jedem Start neue Zertifikate angefordert
|
||||
# (Let's-Encrypt-Limits!).
|
||||
- ${CADDY_DIR:-./data/caddy}:/data
|
||||
- ${CADDY_CONFIG_DIR:-./data/caddy-config}:/config
|
||||
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
container_name: opencrm-adminer
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# OpenCRM Docker Environment
|
||||
# ============================
|
||||
# Copy this file to .env and adjust the values
|
||||
|
||||
# Domain (for Caddy SSL certificate)
|
||||
# Use your actual domain, e.g., crm.example.com
|
||||
DOMAIN=localhost
|
||||
|
||||
# Database
|
||||
# HINWEIS: In diesem Stack wird die Verbindungs-URL direkt aus diesen Werten
|
||||
# zusammengesetzt. Sonderzeichen im Passwort ($ ! # @ : / ?) koennen die URL
|
||||
# zerlegen und den Start verhindern. Nutze hier ein langes Passwort aus
|
||||
# Buchstaben und Ziffern - oder den Stack im Projektstamm, dessen Entrypoint
|
||||
# die Zeichen korrekt kodiert.
|
||||
DB_ROOT_PASSWORD=change-this-root-password
|
||||
DB_NAME=opencrm
|
||||
DB_USER=opencrm
|
||||
DB_PASSWORD=change-this-password
|
||||
|
||||
# JWT Authentication
|
||||
# Generate with: openssl rand -base64 32
|
||||
JWT_SECRET=change-this-to-a-secure-random-string
|
||||
# Access-Token kurz (XSS-Schutz, Token lebt nur im JS-Memory).
|
||||
# Refresh-Token lang im httpOnly-Cookie.
|
||||
JWT_EXPIRES_IN=15m
|
||||
JWT_REFRESH_EXPIRES_IN=7d
|
||||
|
||||
# Encryption Key (for portal credentials)
|
||||
# Generate with: openssl rand -hex 32
|
||||
ENCRYPTION_KEY=change-this-to-a-32-byte-hex-key
|
||||
|
||||
# TLS: In diesem Stack terminiert Caddy das HTTPS. 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).
|
||||
HTTPS_ENABLED=true
|
||||
|
||||
# Nur noetig, wenn das Frontend unter einer ANDEREN Domain laeuft als das
|
||||
# Backend. Beim Standard-Setup (alles hinter derselben Caddy-Domain) leer
|
||||
# lassen.
|
||||
CORS_ORIGINS=
|
||||
|
||||
# Cloud-Deploy: blockt zusaetzlich private IP-Ranges, damit ein eingeloggter
|
||||
# Admin ueber die Provider-/SMTP-Testverbindung keine internen Dienste
|
||||
# anpingen kann. On-Prem meist false, weil Mailserver oft lokal laufen.
|
||||
SSRF_BLOCK_PRIVATE_IPS=false
|
||||
|
||||
# First Install: Set to "true" to seed database on first startup
|
||||
# After first successful start, set back to "false"
|
||||
RUN_SEED=true
|
||||
|
||||
# ---------- Siegel für das Audit-Log ----------
|
||||
# Signiert jeden neuen Audit-Eintrag mit einem Schlüssel ausserhalb der
|
||||
# Datenbank, damit sich die Beweisspur nicht nachtraeglich faelschen laesst.
|
||||
# Generieren: openssl rand -hex 32 (pro Umgebung ein eigener Wert).
|
||||
# Ohne Wert laeuft alles normal weiter, nur ungesiegelt.
|
||||
# Einmal gesetzt nicht wieder entfernen - Details in der README.
|
||||
AUDIT_HMAC_KEY=
|
||||
|
||||
# Nur beim Schluesselwechsel: frueherer Schluessel, mehrere kommagetrennt.
|
||||
AUDIT_HMAC_KEY_OLD=
|
||||
@@ -1,97 +0,0 @@
|
||||
# ===================================
|
||||
# Stage 1: Build Frontend
|
||||
# ===================================
|
||||
FROM node:20-alpine AS frontend-builder
|
||||
|
||||
WORKDIR /app/frontend
|
||||
|
||||
# Copy package files
|
||||
COPY frontend/package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Copy frontend source
|
||||
COPY frontend/ ./
|
||||
|
||||
# Build frontend
|
||||
RUN npm run build
|
||||
|
||||
# ===================================
|
||||
# Stage 2: Build Backend
|
||||
# ===================================
|
||||
FROM node:20-alpine AS backend-builder
|
||||
|
||||
WORKDIR /app/backend
|
||||
|
||||
# Install OpenSSL for Prisma
|
||||
RUN apk add --no-cache openssl
|
||||
|
||||
# Copy package files
|
||||
COPY backend/package*.json ./
|
||||
|
||||
# Install dependencies (including dev for build)
|
||||
RUN npm ci
|
||||
|
||||
# Copy backend source
|
||||
COPY backend/ ./
|
||||
|
||||
# Generate Prisma client
|
||||
RUN npx prisma generate
|
||||
|
||||
# Build TypeScript
|
||||
RUN npm run build
|
||||
|
||||
# ===================================
|
||||
# Stage 3: Production Runtime
|
||||
# ===================================
|
||||
FROM node:20-alpine AS production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install OpenSSL for Prisma runtime and netcat for DB health check
|
||||
RUN apk add --no-cache openssl netcat-openbsd
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S opencrm -u 1001 -G nodejs
|
||||
|
||||
# Copy backend package files
|
||||
COPY backend/package*.json ./
|
||||
|
||||
# Install production dependencies + tsx for seed script
|
||||
RUN npm ci --omit=dev && npm install tsx
|
||||
|
||||
# Copy Prisma schema and generate client
|
||||
COPY backend/prisma ./prisma
|
||||
RUN npx prisma generate
|
||||
|
||||
# Copy built backend
|
||||
COPY --from=backend-builder /app/backend/dist ./dist
|
||||
|
||||
# Copy built frontend to public directory
|
||||
COPY --from=frontend-builder /app/frontend/dist ./public
|
||||
|
||||
# Copy seed file for factory reset
|
||||
COPY backend/prisma/seed.ts ./prisma/
|
||||
|
||||
# Copy entrypoint script
|
||||
COPY docker/entrypoint.sh ./entrypoint.sh
|
||||
|
||||
# Create directories for uploads and backups
|
||||
RUN mkdir -p uploads backups && \
|
||||
chmod +x entrypoint.sh && \
|
||||
chown -R opencrm:nodejs /app
|
||||
|
||||
# Switch to non-root user
|
||||
USER opencrm
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3001
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/api/health || exit 1
|
||||
|
||||
# Start the application with entrypoint
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
@@ -1,139 +0,0 @@
|
||||
# OpenCRM Docker Deployment
|
||||
|
||||
## Schnellstart
|
||||
|
||||
1. **Umgebungsvariablen konfigurieren:**
|
||||
```bash
|
||||
cd docker
|
||||
cp .env.example .env
|
||||
nano .env # Sichere Werte setzen
|
||||
```
|
||||
|
||||
2. **Container starten (erster Start mit RUN_SEED=true):**
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Beim ersten Start wird automatisch:
|
||||
- Auf die Datenbank gewartet
|
||||
- Migrationen ausgeführt
|
||||
- Seed-Daten geladen (wenn `RUN_SEED=true`)
|
||||
|
||||
3. **Nach erfolgreicher Installation:**
|
||||
```bash
|
||||
# RUN_SEED in .env auf false setzen
|
||||
sed -i 's/RUN_SEED=true/RUN_SEED=false/' .env
|
||||
```
|
||||
|
||||
4. **Anwendung aufrufen:**
|
||||
- Mit Domain: `https://your-domain.com`
|
||||
- Lokal: `http://localhost`
|
||||
|
||||
5. **Login:**
|
||||
- E-Mail: `admin@admin.com`
|
||||
- Passwort: `admin`
|
||||
|
||||
## Architektur
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Caddy │
|
||||
│ (SSL/TLS) │
|
||||
│ :80/:443 │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ OpenCRM │
|
||||
│ (Node.js) │
|
||||
│ :3001 │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ MariaDB │
|
||||
│ :3306 │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
## Befehle
|
||||
|
||||
### Container verwalten
|
||||
```bash
|
||||
# Starten
|
||||
docker compose up -d
|
||||
|
||||
# Stoppen
|
||||
docker compose down
|
||||
|
||||
# Logs anzeigen
|
||||
docker compose logs -f app
|
||||
|
||||
# Neustart
|
||||
docker compose restart app
|
||||
```
|
||||
|
||||
### Datenbank
|
||||
```bash
|
||||
# Migration ausführen
|
||||
docker compose exec app npx prisma migrate deploy
|
||||
|
||||
# Seed-Daten laden
|
||||
docker compose exec app npx tsx prisma/seed.ts
|
||||
|
||||
# Prisma Studio (Datenbank-UI)
|
||||
docker compose exec app npx prisma studio
|
||||
```
|
||||
|
||||
### Backup & Restore
|
||||
```bash
|
||||
# Backup-Verzeichnis ist unter /app/backups gemountet
|
||||
# Backups werden über die Anwendung erstellt/wiederhergestellt
|
||||
```
|
||||
|
||||
### Update
|
||||
```bash
|
||||
# Image neu bauen und Container aktualisieren
|
||||
docker compose build --no-cache
|
||||
docker compose up -d
|
||||
# Migrationen werden automatisch beim Start ausgeführt
|
||||
```
|
||||
|
||||
## Volumes
|
||||
|
||||
| Volume | Beschreibung |
|
||||
|--------|--------------|
|
||||
| `mariadb_data` | Datenbank-Dateien |
|
||||
| `uploads_data` | Hochgeladene Dokumente |
|
||||
| `backups_data` | Backup-Dateien |
|
||||
| `caddy_data` | SSL-Zertifikate |
|
||||
| `caddy_config` | Caddy-Konfiguration |
|
||||
|
||||
## SSL-Zertifikat
|
||||
|
||||
Caddy holt automatisch ein Let's Encrypt Zertifikat wenn:
|
||||
- Die Domain in `.env` korrekt gesetzt ist
|
||||
- Port 80 und 443 von außen erreichbar sind
|
||||
- DNS auf den Server zeigt
|
||||
|
||||
Für lokale Entwicklung mit `DOMAIN=localhost` wird ein selbstsigniertes Zertifikat verwendet.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container startet nicht
|
||||
```bash
|
||||
docker compose logs app
|
||||
```
|
||||
|
||||
### Datenbank-Verbindung fehlgeschlagen
|
||||
```bash
|
||||
# Warten bis MariaDB bereit ist
|
||||
docker compose logs db
|
||||
```
|
||||
|
||||
### SSL-Zertifikat Probleme
|
||||
```bash
|
||||
docker compose logs caddy
|
||||
# Caddy-Daten zurücksetzen
|
||||
docker compose down
|
||||
docker volume rm opencrm_caddy_data opencrm_caddy_config
|
||||
docker compose up -d
|
||||
```
|
||||
@@ -1,107 +0,0 @@
|
||||
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:
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "=== OpenCRM Startup ==="
|
||||
|
||||
# Wait for database to be ready
|
||||
echo "Waiting for database connection..."
|
||||
MAX_RETRIES=30
|
||||
RETRY_COUNT=0
|
||||
|
||||
while ! nc -z db 3306 2>/dev/null; do
|
||||
RETRY_COUNT=$((RETRY_COUNT + 1))
|
||||
if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then
|
||||
echo "Error: Database not available after $MAX_RETRIES attempts"
|
||||
exit 1
|
||||
fi
|
||||
echo " Attempt $RETRY_COUNT/$MAX_RETRIES - waiting..."
|
||||
sleep 2
|
||||
done
|
||||
echo "Database is ready!"
|
||||
|
||||
# Run migrations
|
||||
echo "Running database migrations..."
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Seed database if RUN_SEED is set (first install)
|
||||
if [ "$RUN_SEED" = "true" ]; then
|
||||
echo "Seeding database..."
|
||||
npx tsx prisma/seed.ts
|
||||
fi
|
||||
|
||||
# Einmal-Bereinigung für Pentest-Reste (Runde 12): XSS-Strings aus
|
||||
# Customer/User-Feldern entfernen + unbekannte AppSettings löschen.
|
||||
# Idempotent – läuft bei jedem Container-Start ohne Risiko.
|
||||
echo "Running data cleanup..."
|
||||
npx tsx prisma/cleanup-xss-and-mass-assignment.ts || echo " (Cleanup übersprungen, nicht-kritisch)"
|
||||
|
||||
# Start the application
|
||||
echo "Starting OpenCRM server..."
|
||||
exec node dist/index.js
|
||||
Reference in New Issue
Block a user