services: backend: build: context: ../backend dockerfile: Dockerfile environment: - OPENAI_API_KEY=${OPENAI_API_KEY:-} - FLARESOLVERR_URL=http://flaresolverr:8191/v1 volumes: - db_data:/app/data restart: unless-stopped depends_on: - flaresolverr networks: - internal healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"] interval: 30s timeout: 10s retries: 3 # Solves Cloudflare's JS challenge via a headless browser — ForexFactory started 403'ing # the backend's direct scraper requests (datacenter IP gets a much harder challenge than # a residential browser). Internal-only, reached by the backend over the docker network. flaresolverr: image: ghcr.io/flaresolverr/flaresolverr:latest environment: - LOG_LEVEL=info restart: unless-stopped networks: - internal frontend: build: context: ../frontend dockerfile: Dockerfile restart: unless-stopped networks: - internal nginx: image: nginx:1.27-alpine ports: - "80:80" - "443:443" volumes: - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro - ./nginx/certs:/etc/letsencrypt:ro - ./nginx/certbot-webroot:/var/www/certbot:ro depends_on: - backend - frontend restart: unless-stopped networks: - internal volumes: db_data: networks: internal: driver: bridge