services: gateway: image: ferronserver/ferron:3 # -c points at our file explicitly so the image's default site never loads. # (absolute binary path: the image is distroless, no $PATH lookup) command: ["/usr/local/bin/ferron", "run", "-c", "/etc/ferron/conf.d/ferron.conf"] ports: - "8080:80" volumes: - ./gateway:/etc/ferron/conf.d:ro - ./frontend:/var/www/frontend:ro depends_on: - auth - catalog - orders - notifications - redis restart: unless-stopped auth: build: ./services/auth environment: PORT: 8001 DATABASE_URL: postgresql://shop:shoppass@postgres:5432/shopdb JWT_SECRET: ${JWT_SECRET:-dev-secret-change-me} depends_on: postgres: condition: service_healthy restart: unless-stopped catalog: build: ./services/catalog environment: PORT: 8002 DATABASE_URL: postgresql://shop:shoppass@postgres:5432/shopdb JWT_SECRET: ${JWT_SECRET:-dev-secret-change-me} depends_on: postgres: condition: service_healthy restart: unless-stopped orders: build: ./services/orders environment: PORT: 8003 DATABASE_URL: postgresql://shop:shoppass@postgres:5432/shopdb JWT_SECRET: ${JWT_SECRET:-dev-secret-change-me} RABBITMQ_URL: amqp://guest:guest@rabbitmq:5672/ depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy restart: unless-stopped notifications: build: ./services/notifications environment: PORT: 8004 DATABASE_URL: postgresql://shop:shoppass@postgres:5432/shopdb JWT_SECRET: ${JWT_SECRET:-dev-secret-change-me} RABBITMQ_URL: amqp://guest:guest@rabbitmq:5672/ depends_on: postgres: condition: service_healthy rabbitmq: condition: service_healthy restart: unless-stopped postgres: image: postgres:16-alpine environment: POSTGRES_USER: shop POSTGRES_PASSWORD: shoppass POSTGRES_DB: shopdb volumes: - pgdata:/var/lib/postgresql/data - ./db/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U shop -d shopdb"] interval: 5s timeout: 3s retries: 10 restart: unless-stopped # Distributed rate-limiting backend for the Ferron gateway (token buckets # live here so every gateway replica shares the same counters). redis: image: redis:7-alpine command: ["redis-server", "--appendonly", "yes"] volumes: - redisdata:/data restart: unless-stopped rabbitmq: image: rabbitmq:3-management-alpine ports: - "15672:15672" # management UI: http://localhost:15672 (guest/guest) volumes: - rabbitdata:/var/lib/rabbitmq healthcheck: test: ["CMD", "rabbitmq-diagnostics", "ping"] interval: 10s timeout: 5s retries: 10 restart: unless-stopped volumes: pgdata: redisdata: rabbitdata: