services: db: image: postgres:16.15-alpine restart: unless-stopped # Nur relevant, wenn DATABASE_PROVIDER=postgresql (Standard) — bei mysql # stattdessen "docker compose --profile mysql up -d db-mysql" starten, # siehe README, Abschnitt "Datenbank-Provider wechseln". environment: POSTGRES_USER: ${POSTGRES_USER:-wabenhain} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD muss in .env gesetzt sein} POSTGRES_DB: ${POSTGRES_DB:-wabenhain} ports: # Nur an localhost binden statt an alle Interfaces — die App erreicht # die DB ueber das interne Compose-Netzwerk, dieser Port dient nur # lokalem Debugging (z.B. per psql/DB-GUI vom selben Host aus). - "127.0.0.1:5432:5432" volumes: - wabenhain_db_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-wabenhain}"] interval: 5s timeout: 5s retries: 10 # Alternative zu "db": nur starten, wenn DATABASE_PROVIDER=mysql in .env # gesetzt ist ("docker compose --profile mysql up -d db-mysql"). Laeuft # nicht automatisch mit "docker compose up" mit, um den Postgres-Standardfall # nicht zu verlangsamen. db-mysql: image: mysql:8.4.11 profiles: ["mysql"] restart: unless-stopped environment: MYSQL_USER: ${MYSQL_USER:-wabenhain} MYSQL_PASSWORD: ${MYSQL_PASSWORD:?MYSQL_PASSWORD muss in .env gesetzt sein, falls DATABASE_PROVIDER=mysql} MYSQL_DATABASE: ${MYSQL_DATABASE:-wabenhain} MYSQL_ALLOW_EMPTY_PASSWORD: "no" MYSQL_RANDOM_ROOT_PASSWORD: "yes" ports: - "127.0.0.1:3306:3306" volumes: - wabenhain_db_mysql_data:/var/lib/mysql healthcheck: test: ["CMD-SHELL", "mysqladmin ping -h localhost -u${MYSQL_USER:-wabenhain} -p${MYSQL_PASSWORD}"] interval: 5s timeout: 5s retries: 10 # Einziger nach aussen exponierter Dienst: terminiert die Client-Verbindung # und setzt X-Forwarded-For dabei neu (verwirft einen vom Client selbst # mitgeschickten Wert, siehe Caddyfile-Kommentar). Ohne diesen Proxy koennte # "app" direkt erreicht werden und jedes Rate-Limit (Login, 2FA, Checkout) # liesse sich durch einen gefaelschten X-Forwarded-For-Header umgehen. proxy: image: caddy:2.11.4-alpine restart: unless-stopped depends_on: - app ports: - "80:80" # Fuer echtes HTTPS mit eigener Domain zusaetzlich freigeben und # SITE_ADDRESS in .env auf die Domain setzen (siehe Caddyfile): # - "443:443" # - "443:443/udp" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - wabenhain_caddy_data:/data environment: SITE_ADDRESS: ${SITE_ADDRESS:-} app: build: context: . dockerfile: Dockerfile restart: unless-stopped depends_on: db: condition: service_healthy required: false expose: - "3000" environment: # DATABASE_URL kommt komplett aus .env — je nach DATABASE_PROVIDER # entweder die Postgres- ("db"-Service, Port 5432) oder die # MySQL-Verbindungszeichenkette ("db-mysql"-Service, Port 3306). DATABASE_PROVIDER: ${DATABASE_PROVIDER:-postgresql} DATABASE_URL: ${DATABASE_URL} STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} STRIPE_PUBLISHABLE_KEY: ${STRIPE_PUBLISHABLE_KEY} STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET} # Nur fuer den Seed-Schritt relevant (legt das initiale Admin-Konto an, # siehe README "Admin-Zugang") — kein Basic-Auth-Geheimnis mehr. Bewusst # OHNE Default-Wert: ein vorhersehbarer Wert wie "admin@wabenhain.com" # liesse sich vor dem ersten Deploy-Seed-Lauf selbst registrieren, siehe # prisma/seed.ts fuer die zusaetzliche Absicherung dagegen. ADMIN_EMAIL: ${ADMIN_EMAIL:?ADMIN_EMAIL muss in .env gesetzt sein} ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD muss in .env gesetzt sein} SESSION_SECRET: ${SESSION_SECRET:?SESSION_SECRET muss in .env gesetzt sein} GOOGLE_PLACES_API_KEY: ${GOOGLE_PLACES_API_KEY} GOOGLE_PLACE_ID: ${GOOGLE_PLACE_ID} SMTP_HOST: ${SMTP_HOST} SMTP_PORT: ${SMTP_PORT:-587} SMTP_USER: ${SMTP_USER} SMTP_PASSWORD: ${SMTP_PASSWORD} SMTP_FROM: ${SMTP_FROM:-Wabenhain } NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL:-http://localhost:3000} NODE_ENV: production volumes: wabenhain_db_data: wabenhain_db_mysql_data: wabenhain_caddy_data: