# Production overlay for LegacyHUB. # # Usage: # cp .env.prod.example .env.prod # $EDITOR .env.prod # rotate every credential # docker compose \ # -f docker-compose.yml -f docker-compose.prod.yml \ # --env-file .env.prod \ # up -d --build --force-recreate # # This overlay narrows the dev-friendly defaults: # - removes published ports from data services (only api stays public); # - turns on the OpenSearch security plugin and forces an admin password; # - requires CORS_ALLOWED_ORIGINS to be set (no localhost fallback); # - bumps Java + worker concurrency for real workloads; # - drops the MinIO console. services: postgres: ports: !reset [] environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set} restart: always minio: command: server /data ports: !reset [] environment: MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:?MINIO_ACCESS_KEY must be set} MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:?MINIO_SECRET_KEY must be set} restart: always opensearch: ports: !reset [] environment: - discovery.type=single-node - bootstrap.memory_lock=true - "OPENSEARCH_JAVA_OPTS=-Xms2g -Xmx2g" - DISABLE_INSTALL_DEMO_CONFIG=true - plugins.security.disabled=false - OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_ADMIN_PASSWORD:?OPENSEARCH_ADMIN_PASSWORD must be set} restart: always qdrant: ports: !reset [] environment: QDRANT__SERVICE__API_KEY: ${QDRANT_API_KEY:?QDRANT_API_KEY must be set} restart: always redis: ports: !reset [] restart: always api: environment: <<: &prod-env POSTGRES_HOST: ${POSTGRES_HOST} POSTGRES_PORT: ${POSTGRES_PORT} POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} MINIO_ENDPOINT: ${MINIO_ENDPOINT} MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} MINIO_BUCKET_ORIGINALS: ${MINIO_BUCKET_ORIGINALS} MINIO_BUCKET_DERIVED: ${MINIO_BUCKET_DERIVED} MINIO_SECURE: "true" OPENSEARCH_HOST: ${OPENSEARCH_HOST} OPENSEARCH_PORT: ${OPENSEARCH_PORT} OPENSEARCH_USE_SSL: "true" OPENSEARCH_VERIFY_CERTS: "true" OPENSEARCH_USER: ${OPENSEARCH_USER} OPENSEARCH_PASSWORD: ${OPENSEARCH_PASSWORD} OPENSEARCH_INDEX_CHUNKS: ${OPENSEARCH_INDEX_CHUNKS} QDRANT_HOST: ${QDRANT_HOST} QDRANT_PORT: ${QDRANT_PORT} QDRANT_API_KEY: ${QDRANT_API_KEY} QDRANT_COLLECTION_CHUNKS: ${QDRANT_COLLECTION_CHUNKS} REDIS_URL: ${REDIS_URL} OCR_LANGUAGES: ${OCR_LANGUAGES} OCR_ENABLED: ${OCR_ENABLED} DOCLING_OCR_ENABLED: ${DOCLING_OCR_ENABLED} MAX_DOCUMENT_TIMEOUT_SECONDS: ${MAX_DOCUMENT_TIMEOUT_SECONDS} EMBEDDING_MODEL: ${EMBEDDING_MODEL} EMBEDDING_DEVICE: ${EMBEDDING_DEVICE} RERANKER_MODEL: ${RERANKER_MODEL} RERANKER_DEVICE: ${RERANKER_DEVICE} RERANKER_ENABLED: ${RERANKER_ENABLED} APP_LOG_LEVEL: ${APP_LOG_LEVEL} APP_INPUT_DIR: /data/input APP_WORK_DIR: /data/work CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:?CORS_ALLOWED_ORIGINS must be set (no * in production)} restart: always worker: command: ["celery", "-A", "app.workers.celery_app", "worker", "--loglevel=INFO", "--concurrency=4"] environment: <<: *prod-env restart: always