name: sluc-business-club services: db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: sbc POSTGRES_USER: postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} APP_DB_PASSWORD: ${APP_DB_PASSWORD:?set APP_DB_PASSWORD in .env} volumes: - db_data:/var/lib/postgresql/data - ./db/init:/docker-entrypoint-initdb.d:ro networks: - backend healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d sbc"] interval: 5s timeout: 3s retries: 12 # No published ports: the database is reachable only from the backend network. api: build: ./server restart: unless-stopped environment: NODE_ENV: production PORT: "3000" DATABASE_URL: postgres://sbc_app:${APP_DB_PASSWORD}@db:5432/sbc JWT_SECRET: ${JWT_SECRET:?set JWT_SECRET in .env} ADMIN_INITIAL_PASSWORD: ${ADMIN_INITIAL_PASSWORD:-} MEMBER_INITIAL_PASSWORD: ${MEMBER_INITIAL_PASSWORD:-} COOKIE_SECURE: ${COOKIE_SECURE:-false} UPLOAD_DIR: /data/uploads volumes: - uploads:/data/uploads depends_on: db: condition: service_healthy networks: - backend - frontend read_only: true tmpfs: - /tmp security_opt: - no-new-privileges:true healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"] interval: 10s timeout: 5s retries: 6 web: build: ./web restart: unless-stopped ports: - "${WEB_PORT:-8080}:8080" volumes: - uploads:/var/www/uploads:ro depends_on: - api networks: - frontend security_opt: - no-new-privileges:true networks: backend: # internal: the db network never routes to the outside world internal: true frontend: volumes: db_data: uploads: