services: backend: build: context: ./backend dockerfile: Dockerfile.prod depends_on: db: condition: service_healthy environment: - DATABASE_URL=${DATABASE_URL} - ODH_LICENCE_KEY=${ODH_LICENCE_KEY} - TZ=Europe/Berlin volumes: # Working directory inside Dockerfile.prod is /app — must match the # frontend's mount of the same host path below, since that's how # downloaded media becomes visible to the frontend at all. - ./backend/public/storage:/app/public/storage restart: unless-stopped healthcheck: # Distroless has no shell/wget/curl, so the binary checks itself — # see the `healthcheck` subcommand in cmd/server/main.go. test: ["CMD", "/app/vindn-backend", "healthcheck"] interval: 30s timeout: 5s retries: 3 start_period: 15s db: image: postgres:14 environment: POSTGRES_USER: ${POSTGRES_USER:-postgres} # No insecure default here on purpose — POSTGRES_PASSWORD must be set # in this environment's own .env (matching the credentials embedded # in DATABASE_URL), so a prod deploy fails loudly instead of quietly # running on the well-known "postgres" password. POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in .env} POSTGRES_DB: ${POSTGRES_DB:-postgres} # ports: # - "5432:5432" volumes: - ./pgdata:/var/lib/postgresql/data restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] interval: 10s timeout: 5s retries: 5 frontend: env_file: - .env-frontend build: context: ./frontend dockerfile: Dockerfile.prod depends_on: db: condition: service_healthy environment: - DATABASE_URL=${DATABASE_URL} - APP_ENV=prod - APP_DEBUG=0 volumes: - ./backend/public/storage:/app/public/storage restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/"] interval: 30s timeout: 5s retries: 3 start_period: 15s networks: - traefik - default labels: - "traefik.enable=true" - "traefik.docker.network=traefik-docker_default" - "traefik.http.routers.vindn.rule=Host(`${VIRTUAL_HOST}`) || Host(`www.${VIRTUAL_HOST}`)" - "traefik.http.routers.vindn.entrypoints=websecure" - "traefik.http.routers.vindn.tls.certresolver=letsencrypt" - "traefik.http.services.vindn.loadbalancer.server.port=8000" - "traefik.http.routers.vindn.tls=true" - "traefik.http.routers.vindn.middlewares=www-redirect-reverse_vindn" - "traefik.http.middlewares.www-redirect-reverse_vindn.redirectregex.permanent=true" - "traefik.http.middlewares.www-redirect-reverse_vindn.redirectregex.regex=^https?://${VIRTUAL_HOST}/(.*)" - "traefik.http.middlewares.www-redirect-reverse_vindn.redirectregex.replacement=https://www.${VIRTUAL_HOST}/$${1}" networks: traefik: external: true name: traefik-docker_default