services: db: image: postgis/postgis:16-3.4 environment: POSTGRES_DB: bm POSTGRES_USER: bm POSTGRES_PASSWORD: ${BM_DB_PASSWORD} volumes: - bm_pg_data:/var/lib/postgresql/data networks: - bm_internal healthcheck: test: ["CMD-SHELL", "pg_isready -U bm -d bm"] interval: 10s timeout: 5s retries: 10 redis: image: redis:7-alpine command: ["redis-server", "--appendonly", "yes"] volumes: - bm_redis_data:/data networks: - bm_internal # ✅ SÉCURISÉ : Pre-build avec Dockerfile geocoder-enqueue: build: context: ../apps/geocoder working_dir: /app environment: DATABASE_URL: ${DATABASE_URL} GEOCODE_ENQUEUE_BATCH: "90000" command: ["python", "src/enqueue.py"] networks: - bm_internal restart: "no" # ✅ SÉCURISÉ : Pre-build avec Dockerfile geocoder-worker: build: context: ../apps/geocoder working_dir: /app environment: DATABASE_URL: ${DATABASE_URL} NOMINATIM_BASE: "https://nominatim.openstreetmap.org" NOMINATIM_EMAIL: ${NOMINATIM_EMAIL} NOMINATIM_USER_AGENT: ${NOMINATIM_USER_AGENT} NOMINATIM_MIN_DELAY: "1.05" NOMINATIM_JITTER: "0.35" GEOCODE_MAX_PER_RUN: "5000" command: ["python", "src/worker.py"] networks: - bm_internal restart: unless-stopped pgadmin: image: dpage/pgadmin4:8 environment: PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL} PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD} PGADMIN_CONFIG_SERVER_MODE: "True" volumes: - pgadmin_data:/var/lib/pgadmin networks: - bm_internal - traefik_net labels: - traefik.enable=true - traefik.docker.network=stack-vps_admin - traefik.http.routers.pgadmin.rule=Host(`pgadmin.bm.nicolasfryder.ovh`) - traefik.http.routers.pgadmin.entrypoints=websecure - traefik.http.routers.pgadmin.tls=true - traefik.http.routers.pgadmin.tls.certresolver=le - traefik.http.services.pgadmin.loadbalancer.server.port=80 api: build: context: ../apps/api environment: PORT: "3000" DATABASE_URL: postgresql://bm:${BM_DB_PASSWORD}@db:5432/bm BM_IMPORT_TOKEN: ${BM_IMPORT_TOKEN} depends_on: db: condition: service_healthy volumes: - ./overrides/api/src/server.js:/app/src/server.js:ro networks: - bm_internal - traefik_net labels: - traefik.enable=true - traefik.http.routers.bm-api.rule=Host(`bm.nicolasfryder.ovh`) - traefik.http.routers.bm-api.entrypoints=websecure - traefik.http.routers.bm-api.tls=true - traefik.http.routers.bm-api.tls.certresolver=le # ✅ SÉCURISÉ : Double auth + rate limiting code: image: lscr.io/linuxserver/code-server:latest environment: PUID: "1001" PGID: "1001" TZ: "Europe/Paris" PASSWORD: ${CODESERVER_PASSWORD} SUDO_PASSWORD: ${CODESERVER_PASSWORD} DEFAULT_WORKSPACE: /workspace volumes: - bm_codeserver_config:/config - /srv/stacks/bm:/workspace networks: - bm_internal - traefik_net labels: - traefik.enable=true - traefik.docker.network=stack-vps_admin - traefik.http.routers.bm-code.rule=Host(`code.bm.nicolasfryder.ovh`) - traefik.http.routers.bm-code.entrypoints=websecure - traefik.http.routers.bm-code.tls=true # ✅ AJOUTÉ : Double auth + rate limiting - traefik.http.routers.bm-code.middlewares=code-auth@file,code-ratelimit@file - traefik.http.services.bm-code.loadbalancer.server.port=8443 worker: build: context: ../apps/worker environment: DB_DSN: postgresql://bm:${BM_DB_PASSWORD}@db:5432/bm MA_LIST_URL: https://www.metal-archives.com/lists/FR MA_STATE_PATH: /app/ma_state.json depends_on: db: condition: service_healthy volumes: - /srv/stacks/bm/infra/ma_state.json:/app/ma_state.json:ro networks: - bm_internal restart: "no" networks: traefik_net: external: true name: stack-vps_admin bm_internal: driver: bridge volumes: bm_pg_data: bm_redis_data: bm_codeserver_config: pgadmin_data: