# Mirrors the upstream OpenRAG compose # (https://github.com/langflow-ai/openrag/blob/main/docker-compose.yml) # with one local override: the backend's :8000 port is published so our # Next.js app can call it from the host. services: opensearch: image: langflowai/openrag-opensearch:${OPENRAG_VERSION:-latest} container_name: os # Bypass the upstream wrapper that runs the security demo installer. # We disable the security plugin entirely (option A in setup notes), so # plain http on 9200 is fine for local dev and boot drops to ~30s. entrypoint: ["/usr/share/opensearch/opensearch-docker-entrypoint.sh"] command: ["opensearch"] environment: - discovery.type=single-node # Heap sizing: the openrag image bundles ~25 plugins (ML, AD, neural # search, geospatial, SQL...). 512m caused GC thrash + cluster-event # timeouts ("Failed to create index .plugins-ml-config within 30s"), # 1g caused OOM-kill (exit 137) on tight Docker Desktop allocations. # 1.5g + 256m direct is the sweet spot — needs Docker Desktop set to # at least 4 GB (Settings → Resources). - OPENSEARCH_JAVA_OPTS=-Xms1536m -Xmx1536m -XX:MaxDirectMemorySize=268435456 - DISABLE_SECURITY_PLUGIN=true - DISABLE_INSTALL_DEMO_CONFIG=true ports: - "9200:9200" - "9600:9600" volumes: - opensearch-data:/usr/share/opensearch/data stop_grace_period: 2m healthcheck: test: [ "CMD-SHELL", "curl -s 'http://localhost:9200/_cluster/health' | grep -qE '\"status\":\"(green|yellow)\"'", ] interval: 5s timeout: 5s retries: 30 start_period: 30s restart: unless-stopped docling: # Backend's /router/upload_ingest path POSTs uploaded files to docling-serve # to extract text/tables/images. Without it, ingest fails with # "Cannot connect to docling-serve at http://host.docker.internal:5001". image: quay.io/docling-project/docling-serve-cpu:latest container_name: docling ports: - "5001:5001" environment: - DOCLING_SERVE_HOST=0.0.0.0 - DOCLING_SERVE_PORT=5001 - DOCLING_SERVE_MAX_SYNC_WAIT=300 restart: unless-stopped langflow: image: langflowai/openrag-langflow:${OPENRAG_VERSION:-latest} container_name: langflow depends_on: opensearch: condition: service_healthy docling: condition: service_started ports: - "${LANGFLOW_PORT:-7860}:7860" volumes: - ./flows:/app/flows - ./langflow-data:/app/langflow-data extra_hosts: - "host.docker.internal:host-gateway" environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - WATSONX_APIKEY=${WATSONX_API_KEY} - WATSONX_URL=${WATSONX_URL:-${WATSONX_ENDPOINT}} - WATSONX_PROJECT_ID=${WATSONX_PROJECT_ID} - OLLAMA_BASE_URL=${OLLAMA_ENDPOINT} - LANGFLOW_CONFIG_DIR=/app/langflow-data - LANGFLOW_DATABASE_URL=${LANGFLOW_DATABASE_URL:-sqlite:////app/langflow-data/langflow.db} - LANGFLOW_SECRET_KEY=${LANGFLOW_SECRET_KEY} - LANGFLOW_AUTO_LOGIN=${LANGFLOW_AUTO_LOGIN:-false} - LANGFLOW_SUPERUSER=${LANGFLOW_SUPERUSER:-admin} - LANGFLOW_SUPERUSER_PASSWORD=${LANGFLOW_SUPERUSER_PASSWORD} - LANGFLOW_NEW_USER_IS_ACTIVE=${LANGFLOW_NEW_USER_IS_ACTIVE:-true} - LANGFLOW_ENABLE_SUPERUSER_CLI=${LANGFLOW_ENABLE_SUPERUSER_CLI:-true} - LANGFLOW_WORKERS=${LANGFLOW_WORKERS:-1} - LANGFLOW_LOG_LEVEL=INFO - JWT=None - OWNER=None - OWNER_NAME=None - OWNER_EMAIL=None - CONNECTOR_TYPE=system - CONNECTOR_TYPE_URL=url - DOCUMENT_ID=None - SOURCE_URL=None - ALLOWED_USERS=[] - ALLOWED_GROUPS=[] - OPENRAG-QUERY-FILTER="{}" - OPENSEARCH_PASSWORD=${OPENSEARCH_PASSWORD} - OPENSEARCH_HOST=opensearch - OPENSEARCH_PORT=9200 - OPENSEARCH_URL=http://opensearch:9200 - OPENSEARCH_INDEX_NAME=${OPENSEARCH_INDEX_NAME:-documents} - DOCLING_SERVE_URL=${DOCLING_SERVE_URL:-http://host.docker.internal:5001} - FILENAME=None - MIMETYPE=None - FILESIZE=0 - SELECTED_EMBEDDING_MODEL=${SELECTED_EMBEDDING_MODEL:-text-embedding-3-small} - LANGFLOW_VARIABLES_TO_GET_FROM_ENVIRONMENT=JWT,OPENRAG-QUERY-FILTER,OPENSEARCH_PASSWORD,OPENSEARCH_URL,DOCLING_SERVE_URL,OWNER,OWNER_NAME,OWNER_EMAIL,CONNECTOR_TYPE,DOCUMENT_ID,SOURCE_URL,ALLOWED_USERS,ALLOWED_GROUPS,FILENAME,MIMETYPE,FILESIZE,SELECTED_EMBEDDING_MODEL,OPENAI_API_KEY,ANTHROPIC_API_KEY,WATSONX_APIKEY,WATSONX_URL,WATSONX_PROJECT_ID,OLLAMA_BASE_URL,OPENSEARCH_INDEX_NAME - HIDE_GETTING_STARTED_PROGRESS=true openrag-backend: # Custom build patches the base image to talk to OpenSearch over plain # http with no auth (the upstream image hardcodes use_ssl=True + # http_auth=admin). See docker/openrag-backend.Dockerfile. build: context: . dockerfile: docker/openrag-backend.Dockerfile args: OPENRAG_VERSION: ${OPENRAG_VERSION:-latest} image: notebooklm/openrag-backend:local container_name: openrag-backend depends_on: opensearch: condition: service_healthy langflow: condition: service_started docling: condition: service_started # NOTE: upstream compose does NOT publish 8000 to the host (frontend # reaches it on the docker network). We publish it so our Next.js app, # running on the host, can call /v1/chat/completions and the ingest API. ports: - "8000:8000" environment: - OPENSEARCH_HOST=opensearch - OPENSEARCH_PORT=9200 - OPENSEARCH_USERNAME=${OPENSEARCH_USERNAME:-admin} - OPENSEARCH_PASSWORD=${OPENSEARCH_PASSWORD} - OPENSEARCH_INDEX_NAME=${OPENSEARCH_INDEX_NAME:-documents} - LANGFLOW_URL=http://langflow:7860 - LANGFLOW_PUBLIC_URL=${LANGFLOW_PUBLIC_URL:-http://localhost:7860} - LANGFLOW_AUTO_LOGIN=${LANGFLOW_AUTO_LOGIN:-false} - LANGFLOW_SUPERUSER=${LANGFLOW_SUPERUSER:-admin} - LANGFLOW_SUPERUSER_PASSWORD=${LANGFLOW_SUPERUSER_PASSWORD} - LANGFLOW_KEY=${LANGFLOW_KEY} - LANGFLOW_CHAT_FLOW_ID=${LANGFLOW_CHAT_FLOW_ID} - LANGFLOW_INGEST_FLOW_ID=${LANGFLOW_INGEST_FLOW_ID} - LANGFLOW_URL_INGEST_FLOW_ID=${LANGFLOW_URL_INGEST_FLOW_ID} - DISABLE_INGEST_WITH_LANGFLOW=${DISABLE_INGEST_WITH_LANGFLOW:-true} - INGEST_SAMPLE_DATA=${INGEST_SAMPLE_DATA:-false} - LANGFLOW_OPENSEARCH_HOST=opensearch - LANGFLOW_OPENSEARCH_PORT=9200 - OPENAI_API_KEY=${OPENAI_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - WATSONX_API_KEY=${WATSONX_API_KEY} - WATSONX_ENDPOINT=${WATSONX_ENDPOINT} - WATSONX_PROJECT_ID=${WATSONX_PROJECT_ID} - OLLAMA_ENDPOINT=${OLLAMA_ENDPOINT} - SESSION_SECRET=${SESSION_SECRET} - JWT_SIGNING_KEY=${JWT_SIGNING_KEY} - OPENRAG_ENCRYPTION_KEY=${OPENRAG_ENCRYPTION_KEY} - LOG_LEVEL=${LOG_LEVEL:-INFO} - ENVIRONMENT=${ENVIRONMENT:-production} - LANGFLOW_TIMEOUT=${LANGFLOW_TIMEOUT:-2400} - INGESTION_TIMEOUT=${INGESTION_TIMEOUT:-3600} - UPLOAD_BATCH_SIZE=${UPLOAD_BATCH_SIZE:-25} - MAX_WORKERS=${MAX_WORKERS:-4} - DOCLING_SERVE_URL=${DOCLING_SERVE_URL:-http://docling:5001} volumes: - ./openrag-documents:/app/openrag-documents - ./keys:/app/keys - ./flows:/app/flows - ./flows/backup:/app/flows/backup - ./config:/app/config - ./openrag-data:/app/data extra_hosts: - "host.docker.internal:host-gateway" openrag-frontend: image: langflowai/openrag-frontend:${OPENRAG_VERSION:-latest} container_name: openrag-frontend depends_on: - openrag-backend environment: - OPENRAG_BACKEND_HOST=openrag-backend ports: - "${FRONTEND_PORT:-3000}:3000" volumes: opensearch-data: