services: keycloak: image: quay.io/keycloak/keycloak:26.0 container_name: certifai-keycloak environment: KC_BOOTSTRAP_ADMIN_USERNAME: admin KC_BOOTSTRAP_ADMIN_PASSWORD: admin KC_DB: dev-mem KC_HEALTH_ENABLED: "true" ports: - "8080:8080" command: - start-dev - --import-realm volumes: - ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json:ro - ./keycloak/themes/certifai:/opt/keycloak/themes/certifai:ro healthcheck: test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /realms/master HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && head -1 <&3 | grep -q '200 OK'"] interval: 10s timeout: 5s retries: 10 start_period: 30s mongo: image: mongo:latest restart: unless-stopped ports: - 27017:27017 environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: example searxng: image: searxng/searxng:latest container_name: certifai-searxng restart: unless-stopped ports: - "8888:8080" environment: - SEARXNG_BASE_URL=http://localhost:8888 volumes: - ./searxng:/etc/searxng:rw librechat: image: ghcr.io/danny-avila/librechat:latest container_name: certifai-librechat restart: unless-stopped # Use host networking so localhost:8080 (Keycloak) is reachable for # OIDC discovery, and the browser redirect URLs match the issuer. network_mode: host depends_on: keycloak: condition: service_healthy mongo: condition: service_started environment: # MongoDB (use localhost since we're on host network) MONGO_URI: mongodb://root:example@localhost:27017/librechat?authSource=admin DOMAIN_CLIENT: http://localhost:3080 DOMAIN_SERVER: http://localhost:3080 # Allow HTTP for local dev OIDC (Keycloak on localhost without TLS) NODE_TLS_REJECT_UNAUTHORIZED: "0" NODE_ENV: development # Keycloak OIDC SSO OPENID_ISSUER: http://localhost:8080/realms/certifai OPENID_CLIENT_ID: certifai-librechat OPENID_CLIENT_SECRET: certifai-librechat-secret OPENID_SESSION_SECRET: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6" OPENID_CALLBACK_URL: /oauth/openid/callback OPENID_SCOPE: openid profile email OPENID_BUTTON_LABEL: Login with CERTifAI OPENID_AUTH_EXTRA_PARAMS: prompt=none # Disable local auth (SSO only) ALLOW_EMAIL_LOGIN: "false" ALLOW_REGISTRATION: "false" ALLOW_SOCIAL_LOGIN: "true" ALLOW_SOCIAL_REGISTRATION: "true" # JWT / encryption secrets (required by LibreChat) CREDS_KEY: "97e95d72cdda06774a264f9fb7768097a6815dc1e930898d2e39c9a3a253b157" CREDS_IV: "2ea456ab25279089b0ff9e7aca1df6e6" JWT_SECRET: "767b962176666eab56e180e6f2d3fe95145dc6b978e37d4eb8d1da5421c5fb26" JWT_REFRESH_SECRET: "51a43a1fca4b7b501b37e226a638645d962066e0686b82248921f3160e96501e" # App settings APP_TITLE: CERTifAI Chat CUSTOM_FOOTER: CERTifAI - Sovereign GenAI Infrastructure HOST: 0.0.0.0 PORT: "3080" NO_INDEX: "true" volumes: - ./librechat/librechat.yaml:/app/librechat.yaml:ro - ./librechat/logo.svg:/app/client/public/assets/logo.svg:ro # Patch: allow HTTP issuer for local dev (openid-client v6 enforces HTTPS) - ./librechat/openidStrategy.js:/app/api/strategies/openidStrategy.js:ro - librechat-data:/app/data langflow: image: langflowai/langflow:latest container_name: certifai-langflow restart: unless-stopped ports: - "7860:7860" environment: LANGFLOW_AUTO_LOGIN: "true" langgraph: image: langchain/langgraph-trial:3.12 container_name: certifai-langgraph restart: unless-stopped depends_on: langgraph-db: condition: service_started langgraph-redis: condition: service_started ports: - "8123:8000" environment: DATABASE_URI: postgresql://langgraph:langgraph@langgraph-db:5432/langgraph REDIS_URI: redis://langgraph-redis:6379 langgraph-db: image: postgres:16 container_name: certifai-langgraph-db restart: unless-stopped environment: POSTGRES_USER: langgraph POSTGRES_PASSWORD: langgraph POSTGRES_DB: langgraph volumes: - langgraph-db-data:/var/lib/postgresql/data langgraph-redis: image: redis:7-alpine container_name: certifai-langgraph-redis restart: unless-stopped langfuse: image: langfuse/langfuse:3 container_name: certifai-langfuse restart: unless-stopped depends_on: keycloak: condition: service_healthy langfuse-db: condition: service_healthy langfuse-clickhouse: condition: service_healthy langfuse-redis: condition: service_healthy langfuse-minio: condition: service_healthy ports: - "3000:3000" environment: DATABASE_URL: postgresql://langfuse:langfuse@langfuse-db:5432/langfuse NEXTAUTH_URL: http://localhost:3000 NEXTAUTH_SECRET: certifai-langfuse-dev-secret SALT: certifai-langfuse-dev-salt ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000" # Keycloak OIDC SSO - shared realm with CERTifAI dashboard AUTH_KEYCLOAK_CLIENT_ID: certifai-langfuse AUTH_KEYCLOAK_CLIENT_SECRET: certifai-langfuse-secret AUTH_KEYCLOAK_ISSUER: http://keycloak:8080/realms/certifai AUTH_KEYCLOAK_ALLOW_ACCOUNT_LINKING: "true" # Disable local email/password auth (SSO only) AUTH_DISABLE_USERNAME_PASSWORD: "true" CLICKHOUSE_URL: http://langfuse-clickhouse:8123 CLICKHOUSE_MIGRATION_URL: clickhouse://langfuse-clickhouse:9000 CLICKHOUSE_USER: clickhouse CLICKHOUSE_PASSWORD: clickhouse CLICKHOUSE_CLUSTER_ENABLED: "false" REDIS_HOST: langfuse-redis REDIS_PORT: "6379" REDIS_AUTH: langfuse-dev-redis LANGFUSE_S3_EVENT_UPLOAD_BUCKET: langfuse LANGFUSE_S3_EVENT_UPLOAD_REGION: auto LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: minio LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: miniosecret LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: http://langfuse-minio:9000 LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: "true" LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: langfuse LANGFUSE_S3_MEDIA_UPLOAD_REGION: auto LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: minio LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: miniosecret LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: http://langfuse-minio:9000 LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: "true" langfuse-db: image: postgres:16 container_name: certifai-langfuse-db restart: unless-stopped environment: POSTGRES_USER: langfuse POSTGRES_PASSWORD: langfuse POSTGRES_DB: langfuse volumes: - langfuse-db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U langfuse"] interval: 5s timeout: 5s retries: 10 langfuse-clickhouse: image: clickhouse/clickhouse-server:latest container_name: certifai-langfuse-clickhouse restart: unless-stopped user: "101:101" environment: CLICKHOUSE_DB: default CLICKHOUSE_USER: clickhouse CLICKHOUSE_PASSWORD: clickhouse ulimits: nofile: soft: 262144 hard: 262144 volumes: - langfuse-clickhouse-data:/var/lib/clickhouse - langfuse-clickhouse-logs:/var/log/clickhouse-server healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1"] interval: 5s timeout: 5s retries: 10 langfuse-redis: image: redis:7-alpine container_name: certifai-langfuse-redis restart: unless-stopped command: redis-server --requirepass langfuse-dev-redis healthcheck: test: ["CMD", "redis-cli", "-a", "langfuse-dev-redis", "ping"] interval: 5s timeout: 5s retries: 10 langfuse-minio: image: cgr.dev/chainguard/minio container_name: certifai-langfuse-minio restart: unless-stopped entrypoint: sh command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data' environment: MINIO_ROOT_USER: minio MINIO_ROOT_PASSWORD: miniosecret healthcheck: test: ["CMD-SHELL", "mc ready local || exit 1"] interval: 5s timeout: 5s retries: 10 volumes: librechat-data: langgraph-db-data: langfuse-db-data: langfuse-clickhouse-data: langfuse-clickhouse-logs: