Installation & Configuration Guide

End-to-end GENIE.AI installation: prerequisites, base install, environment configuration, and post-deploy verification.

This is the canonical end-to-end install procedure for GENIE.AI. Choose the deployment model that matches your case before reading on — each model has a dedicated sibling guide with the platform-specific mechanics, while this doc is the universal prerequisite + configuration + verification backbone:

ModelWhen to use itCompanion guide
Docker Compose (docker compose up)Local dev, MVP, small single-host production, evaluationDocker Compose Setup
Docker Swarm (docker stack deploy)Production multi-node, HA, mixed CPU/GPU node placementDocker Swarm Setup
Ansible + SwarmRepeatable fleet deploys with per-environment secretsAnsible README
Remote GPU (GPU_NODE_HOST=)OPEA orchestrators on CPU node, vLLM/TEI on a separate GPU nodeRemote GPU Node

GPU profiles (T4 16 GB / RTX 6000 24 GB / A40 48 GB / H100) layer on top of any of the above via the env.t4 / env.rtx6000 overrides — see GPU Deployment.

Goal

Read this doc top-to-bottom on first install to learn every prerequisite, the environment-variable reference, and the post-deploy verification checklist; afterwards use the cross-linked deployer guides above for incremental changes. Provision a working GENIE.AI stack (NGINX → Kong → backend → OPEA services → ArangoDB) in one sitting, verify every service is healthy, and position yourself for knowledge-base population.

For data-curation guidance (which this guide does not cover) see Content Guidance and Labelling Taxonomy.

For mobile-app build and distribution see Mobile Deployment Guide.

Glossary

TermMeaning
AQLArangoDB Query Language — SQL-like query language for ArangoDB
DGPR-compliantCompliant with the Digital Public Goods standard (alternate spelling — see DPG)
DPG-compliantCompliant with the Digital Public Goods standard
DPGDigital Public Good
KongOpen-source API gateway used as the public entry point
MECEMutually Exclusive, Collectively Exhaustive (hierarchy design principle)
MMRMaximal Marginal Relevance — diversity-aware retrieval reranking
OPEAOpen Platform for Enterprise AI (https://opea.dev)
OIDCOpenID Connect — identity layer on top of OAuth 2.0
RAGRetrieval-Augmented Generation
TEIText Embeddings Inference (Hugging Face’s embedding/rerank server)
vLLMHigh-throughput LLM inference engine

Architecture at a glance

flowchart LR
    User([End user]) -->|HTTPS 443| NGINX
    NGINX --> Kong[Kong API gateway]
    Kong -->|OIDC| Keycloak[Keycloak IdP]
    Kong -->|/api| Backend[Node.js BFF]
    Kong -->|/api| DocRepo[Document repository]
    Backend --> Arango[(ArangoDB<br/>graphs + vectors)]
    DocRepo --> Arango
    DocRepo --> ClamAV[ClamAV]
    DocRepo --> Dataprep
    Dataprep -->|LLM labeling| vLLM
    Dataprep --> Embedding[TEI Embedding]
    Backend --> ChatQnA[ChatQnA orchestrator]
    ChatQnA --> Retriever
    Retriever --> Arango
    ChatQnA --> Reranker[TEI Reranker]
    ChatQnA --> vLLM[vLLM LLM]
    ChatQnA -.optional streaming translation.-> vLLMTrans[vLLM Translation]
    Backend --> Redis[(Redis cache)]

NGINX is the only host-published port (80/443); everything else stays on the internal Docker network. The observability profile adds VictoriaMetrics, VictoriaTraces, tempo-proxy, and Grafana on top of the always-on OTel Collector

  • VictoriaLogs log substrate.

Step 1: Hardware requirements

GENIE.AI needs significant computational resources for AI model inference. The solution will not run reliably without the resources below.

TierCPURAMGPUUse case
Small8 vCPU16 GBT4 16 GB (or none for CPU-only)Dev, MVP, small knowledge base (< 1k chunks)
Medium16 vCPU32 GBRTX 6000 24 GBProduction single-node
Large32 vCPU64 GBA40 48 GB / H100Multi-node production with high concurrency

For the GPU-specific layer, see GPU Deployment.

Step 2: Software prerequisites

  • Ubuntu Linux 22.04 — primary tested platform. Other Debian-based distributions work but may need package-name adjustments.
  • Docker & Docker Swarm — required for orchestrating the containerized services. See Step 3.
  • NVIDIA Drivers & CUDA — required only if using GPU services (vLLM, TEI). See GPU Deployment and NVIDIA A40 Install Guide.
  • Node.js 22+ — required for JavaScript tooling. Docker images use node:22; CI lint+test jobs run on node:20-alpine.

Step 3: Install Docker on every host

3a. Update and install prerequisites

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg

3b. Add Docker’s official GPG key

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

3c. Add the Docker repository

Note: Use https://download.docker.com/linux/ubuntu on Ubuntu (not /linux/debian) — the repo URL must match your distribution.

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

3d. Install Docker Engine

This also removes conflicting older versions like docker.io if present:

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
                        docker-buildx-plugin docker-compose-plugin

3e. Start and enable Docker

If the installer does not start the daemon automatically:

sudo systemctl start docker
sudo systemctl enable docker

3f. Grant your user Docker permissions

sudo usermod -aG docker $USER
newgrp docker

3g. Verify

docker run hello-world

Step 4: Install Node.js 22+

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v   # v22.x
npm -v    # 10.x

Step 5: Clone the repository

git clone https://opensource.unicc.org/un/itu/genie-ai.git
cd genie-ai

If you plan to commit changes, clone from your fork; check with the administrator about which branch is current. The canonical mirror is at https://opensource.unicc.org/un/itu/genie-ai/.

Step 6: Environment configuration

cp env .env

The env template is the single source of truth for configuration. Three templates ship in the repository:

FilePurpose
envDefault deployment — copy to .env first
env.t4NVIDIA T4 GPU overrides — source after .env
env.rtx6000RTX 6000 ADA overrides — source after .env

6a. Generate strong passwords

python3 -c "import secrets; print(secrets.token_urlsafe(32))"

Use this to generate every *_PASSWORD / *_SECRET value. All *_PASSWORD / *_SECRET variables in the .env file are required.

6b. LLM prompt customization (optional)

GENIE.AI uses a two-tier priority for LLM prompts:

  1. ENV VAR (highest): override in .env for deployment-specific customization.
  2. DEFAULT (lowest): built-in prompts in Python code (works out-of-the-box).
VariablePurposeDefault location
CHATQNA_SYSTEM_PROMPTMain ChatQnA system promptgenie-ai-overlay/chatqna/genieai_chatqna.py
CHATQNA_ABSTENTION_INSTRUCTIONSInstructions when no relevant docs foundgenie-ai-overlay/chatqna/genieai_chatqna.py
CHATQNA_ENFORCE_ABSTENTIONEnable/disable abstention behaviorbuilt-in default "true"
LABEL_SELECTOR_SYSTEM_PROMPTRules for automatic document labelinggenie-ai-overlay/dataprep/genieai_dataprep_arangodb.py
CONTEXTUAL_RETRIEVAL_PROMPTPer-chunk doc-context generationgenie-ai-overlay/dataprep/genieai_dataprep_arangodb.py

To customize, add the variable to .env. To change built-in defaults, edit the Python source listed above.

6c. Minimum required variables (TL;DR)

This is the short list a first-time deployer MUST set before running docker stack deploy. Section 6d below is the full reference (200+ vars with defaults, descriptions, and qualifications).

Generate each secret with: python3 -c "import secrets; print(secrets.token_urlsafe(32))"

VariableCategoryPurpose
POSTGRES_PASSWORDPostgreSQL superuserPostgreSQL root password (also used by Kong migrations)
KONG_DB_PASSWORDKongKong’s dedicated PG user password (composed into Kong as KONG_PG_PASSWORD)
ARANGO_PASSWORDArangoDBArangoDB root password (knowledge-base storage)
TRANSLATION_CACHE_PASSWORDRedisRedis cache password (translation cache)
KEYCLOAK_ADMIN_PASSWORDKeycloakKeycloak master admin console password
KEYCLOAK_DB_PASSWORDKeycloakKeycloak dedicated PG user password
KEYCLOAK_CLIENT_SECRETKeycloakOIDC client secret for genie-app
KEYCLOAK_PROXY_CLIENT_SECRETKeycloakService-account secret for the admin API proxy
KC_DATAPREP_CLIENT_SECRETKeycloakService-account secret for dataprep (client_credentials grant)
EMAIL_HOST / EMAIL_PORT / EMAIL_USER / EMAIL_PASSWORD / EMAIL_FROMSMTPRequired for user verification emails
GENIE_ADMIN_PASSWORDInitial adminInitial password for the seeded genie-admin user
HUGGING_FACE_HUB_TOKENGPU onlyHF token to pull vLLM / TEI models
VLLM_API_KEYRemote GPU onlyBearer token for the remote GPU node

6d. Required environment variables

The full variable reference follows. Variables not listed here use compose defaults.

Legend: Required (yes) = must be set in .env before first deploy. Sample <set-me> = replace with your own value; do not ship the example value in production.

General & proxy settings

VariableTypeRequiredDefaultDescription
no_proxystringno(unset)Comma-separated hosts to bypass HTTP proxy
http_proxystringno(unset)HTTP proxy URL (blank if unused)
https_proxystringno(unset)HTTPS proxy URL (blank if unused)

Kong (API gateway) and PostgreSQL

VariableTypeRequiredDefaultDescription
POSTGRES_USERstringnogenieaiPostgreSQL superuser
POSTGRES_DBstringnokongDefault database
POSTGRES_PASSWORDsecretyes<set-me>PostgreSQL superuser password
KONG_DATABASEstringnopostgresTells Kong which DB to use
KONG_PG_HOSTstringnopostgresKong’s PG host
KONG_PG_USERstringnokongKong’s dedicated PG user
KONG_PG_PASSWORDsecretyes<set-me> (= KONG_DB_PASSWORD)Kong PG user password
KONG_PROXY_ACCESS_LOGstringno/dev/stdoutKong proxy access log path
KONG_ADMIN_ACCESS_LOGstringno/dev/stdoutKong admin access log path
KONG_PROXY_ERROR_LOGstringno/dev/stderrKong proxy error log path
KONG_ADMIN_ERROR_LOGstringno/dev/stderrKong admin error log path
KONG_ADMIN_LISTENstringno0.0.0.0:8001, 0.0.0.0:8444 sslKong admin API listen address (see docker-compose.yaml:229)
KONG_DNS_RESOLVERstringno127.0.0.11DNS resolver (Docker internal)
KONG_DNS_ORDERstringnoLAST,A,AAAA,CNAMEDNS resolution order
KONG_TRUSTED_IPSstringno172.16.0.0/12Trusted proxies for X-Forwarded-* headers
KONG_DNS_STALE_TTLnumberno5TTL for stale DNS responses

Frontend (Vue.js)

VariableTypeRequiredDefaultDescription
APP_NAMEstringnohuduma (code fallback)Used by backend database-operations-service.js to prefix backup filenames (${APP_NAME}_backup_<timestamp>); the 'huduma' default is preserved for backward compatibility with existing backups. Use the JSON config files in public/config/ for UI branding instead
FRONTEND_PORTnumberno8090HOST port mapping for the Vue dev server (used only when the 8090:8090 mapping in docker-compose.yaml is uncommented). The frontend container itself listens on PORT (default 8090 baked into the image)
VUE_APP_API_URLstringno/apiPublic URL the frontend uses to reach the API
VUE_PROXY_HOSTstringnolocalhostVue dev proxy target (frontend’s server.js and vue.config.js prepend :3000 when this is unset, so the effective target becomes localhost:3000)
VUE_APP_CSP_CONNECT_SRCstringno'self' http://localhost:3000 http://localhost:8090 http://127.0.0.1:8090 ws://localhost:3000 ws://localhost:8090CSP connect-src allowed origins (frontend build-time via Vue DefinePlugin; must match CSP_CONNECT_SRC)
CSP_CONNECT_SRCstringno'self' http://localhost:3000 http://localhost:8090 http://127.0.0.1:8090 ws://localhost:3000 ws://localhost:8090CSP connect-src for backend Helmet config (must match VUE_APP_CSP_CONNECT_SRC)
CORS_ALLOWED_ORIGINSstringnohttp://localhost:3000,http://localhost:8090,http://127.0.0.1:8090,https://localhostComma-separated CORS origins (compose default includes localhost dev URLs + the resolved NGINX_PUBLIC_DOMAIN)

Backend (Node.js)

VariableTypeRequiredDefaultDescription
NODE_ENVstringnoproductionApplication environment (baked into the backend image)
BACKEND_PORTnumberno3000HOST port mapping for the backend (used only when the 3000:3000 mapping in docker-compose.yaml is uncommented). The backend container itself listens on PORT (default 3000 baked into the image)
API_PREFIXstringno/apiGlobal API prefix
UV_THREADPOOL_SIZEnumberno128Libuv thread-pool size
LOG_LEVELstringnoinfoLogging verbosity
EMAIL_HOSTstringyes (for user verification)<set-me>SMTP server
EMAIL_PORTnumberyes<set-me>SMTP port (587 for TLS, 465 for SSL)
EMAIL_SECUREboolnofalseSMTP TLS/SSL (true for port 465)
EMAIL_USERstringyes<set-me>SMTP username
EMAIL_PASSWORDsecretyes<set-me>SMTP password (Gmail users: 16-char App Password)
EMAIL_FROMstringyes<set-me>From: address on outgoing mail
BACKUP_DIRstringno./database_backupsDB dump output dir (relative to backend cwd; compose bind-mounts ${DATA_DIR:-./data}/database_backups → /app/database_backups so dumps land under ./data/database_backups on the host)
MAX_BACKUPSnumberno5Backups to retain
BACKUP_FORMATstringnojsonBackup format
COMPRESS_BACKUPSboolnofalsegzip backups (true to enable)
CONTEXT_OPTIONstringnoconversation-with-context-labelsConversation-context strategy

Translation & Redis cache

VariableTypeRequiredDefaultDescription
TRANSLATION_THREADSnumberno4Concurrent translation threads
TRANSLATION_BATCHESnumberno5Translation batch size
TRANSLATION_CACHEstringnoon (compose) / off (code)Enable/disable translation cache (on to enable)
TRANSLATION_CACHE_PATHstringno(legacy, unused)Reserved file-based cache path. Current code uses Redis only; set to anything or leave unset
TRANSLATION_CACHE_HOSTstringnoredis-cache (compose) / localhost (code)Redis cache host
TRANSLATION_CACHE_PORTnumberno6379Redis port
TRANSLATION_CACHE_PASSWORDsecretyes<set-me>Redis cache password

ArangoDB (knowledge base)

Note: All GENIE.AI services (backend, frontend, document-repository, OPEA services) share a single ArangoDB database. The default name is genie-ai.

VariableTypeRequiredDefaultDescription
ARANGO_URLstringnohttp://arango-vector-db:8529ArangoDB connection URL
ARANGO_PORTnumberno8529ArangoDB port
ARANGO_DBstringnogenie-aiDatabase name (per-deployment isolation)
ARANGO_USERstringnorootDatabase user (used by backend, doc-repo, db-migrations)
ARANGO_USERNAMEstringnorootParallel to ARANGO_USER for OPEA services (dataprep, retriever) — keep both in sync
ARANGO_PASSWORDsecretyes<set-me>ArangoDB root password
ARANGO_GRAPH_NAMEstringnoGRAPHArangoDB graph name (was RETRIEVER_ARANGO_GRAPH_NAME in v1.3)

Document repository & virus scanning

VariableTypeRequiredDefaultDescription
DOC_REPO_PORTnumberno3001HOST port mapping for document-repository (used only when the 3001:3001 mapping in docker-compose.yaml is uncommented). The doc-repo container itself listens on PORT (default 3001 baked into the image)
DOC_REPO_URLstringnohttp://document-repository:3001 (compose line 1357) / http://localhost:3001 (Python code)Internal URL the chatqna orchestrator uses to reach document-repository. Compose hardcodes the literal http://document-repository:3001 and does NOT propagate DOC_REPO_URL from .env; reading the env var would require editing the compose file. The Python chatqna code reads DOC_REPO_URL via os.getenv("DOC_REPO_URL", "http://localhost:3001") so the value flows through at runtime once it reaches the container
UPLOAD_DIRstringno./uploadsUpload directory (Docker volume is a separate name)
MAX_FILES_UPLOADnumberno10Max files per upload
MAX_FILE_SIZEnumberno52428800Max file size in bytes (~50 MB)
DOCUMENT_INGESTION_LANGUAGEstringnoenIngestion language code
LOG_FILEstringnoapp.logApplication log file name
VIRUS_SCANNINGboolnofalseEnable ClamAV scanning on upload (true to enable)
CLAMSCAN_ACTIVEboolnotrueMaster switch for ClamAV
CLAMSCAN_HOSTstringno127.0.0.1ClamAV host
CLAMSCAN_PORTnumberno3310ClamAV port
CLAMSCAN_TIMEOUTnumberno60000Scan timeout (ms)
CLAMSCAN_REMOVE_INFECTEDboolnofalseAuto-delete infected files
CLAMSCAN_QUARANTINE_INFECTEDboolnofalseQuarantine instead of delete
CLAMSCAN_DEBUG_MODEboolnofalseEnable debug logging
CLAMSCAN_SOCKETboolnofalseUse socket (vs TCP)
CLAMSCAN_LOCAL_FALLBACKboolnotrueFall back to local clamdscan if daemon fails
CLAMSCAN_PATHstringno/usr/bin/clamdscanLocal fallback binary

OPEA & ChatQnA orchestration

VariableTypeRequiredDefaultDescription
NGINX_PORTnumberno80ChatQnA Nginx router port
FRONTEND_SERVICE_IPstringnochatqna-xeon-ui-serverChatQnA UI server hostname
FRONTEND_SERVICE_PORTnumberno5173ChatQnA UI server port (OPEA UI — disabled in GENIE.AI, kept here for reference)
BACKEND_SERVICE_NAMEstringnochatqna-xeon-backend-serverChatQnA backend service name (hardcoded in compose)
BACKEND_SERVICE_IPstringnochatqna-xeon-backend-serverChatQnA backend hostname
BACKEND_SERVICE_PORTnumberno8888ChatQnA backend port
DATAPREP_SERVICE_IPstringnodataprep-arango-serviceDataprep hostname
DATAPREP_SERVICE_PORTnumberno5000Dataprep port
MEGA_SERVICE_HOST_IPstringnochatqna-xeon-backend-serverMega-service orchestrator
CHATQNA_TYPEstringnoChatQnAChatQnA deployment type
EMBEDDING_SERVER_HOST_IPstringnoembeddingOPEA embedding wrapper hostname (port 6000)
EMBEDDING_SERVER_PORTnumberno6000OPEA embedding wrapper port
EMBEDDING_MODEL_IDstringnoBAAI/bge-large-en-v1.5Embedding model
EMBEDDING_SERVER_ENDPOINTstringno/v1/embeddingsEmbedding endpoint path
EMBEDDING_QUERY_INSTRUCTIONSstringno(built-in table)Per-model query-instruction overrides for contrastive / instruction-tuned embedders (issue #1035). Comma-separated substring=instruction pairs; substring is matched case-insensitively against TEI_EMBED_MODEL. Built-in coverage: BAAI/bge-{large,base,small}-{en,zh}-v1.5, hkunlp/instructor, nomic-ai/nomic-embed. See Choosing Models for the full table and override format.
RETRIEVER_SERVICE_HOST_IPstringnoretriever-arango-serviceRetriever hostname
RETRIEVER_SERVICE_PORTnumberno7000Retriever port
RERANK_SERVER_HOST_IPstringnorerankerOPEA reranker wrapper hostname (port 8000)
RERANK_SERVER_PORTnumberno8000OPEA reranker wrapper port
RERANKER_MODEL_IDstringnoBAAI/bge-reranker-v2-m3Reranker model
RERANKING_STRATEGYenumnosliceslice / threshold / slice_threshold / knee_threshold / adaptive
RERANKER_TOP_Nnumberno3Chunks kept by slice strategy
RERANKING_THRESHOLDnumberno0.75Score threshold for the threshold / slice_threshold strategies only (adaptive, the ChatQnA default, ignores it) (compose default 0.75; Python code default 0.9 — compose wins at runtime; set in .env to override)
RERANKER_SCORE_CALIBRATIONenumnononeScore calibration mode
RERANKER_SCORE_TEMPERATUREnumberno1.0Score temperature for calibration
LLM_SERVER_HOST_IPstringnovllmvLLM hostname
LLM_SERVER_PORTnumberno8000vLLM port
VLLM_LLM_MODEL_IDstringnometa-llama/Meta-Llama-3.1-8B-InstructMain LLM model
VLLM_TRANSLATION_MODEL_IDstringnogoogle/gemma-3-4b-itTranslation LLM model
VLLM_TRANSLATION_SERVICE_PORTnumberno9031Translation service port
GUARDRAIL_SERVICE_HOST_IPstringnoguardrailGuardrail hostname
GUARDRAIL_SERVICE_PORTnumberno9090Guardrail port
GUARDRAIL_URLstringnohttp://guardrail:9090/v1/guardrailsGuardrail endpoint
TRANSLATION_SERVICE_HOST_IPstringnovllm-translation-guardrailTranslation service hostname (hardcoded in compose)
TRANSLATION_SERVICE_PORTnumberno9031Translation service port

Note: The DATAPREP_SERVICE_IP and DATAPREP_SERVICE_PORT env vars are consumed by the disabled chatqna-xeon-nginx-server service (replicas: 0); the active dataprep URL is http://dataprep-arango-service:5000 referenced from chatqna env. The guardrail service is part of the opea profile but is also disabled by default (replicas: 0).

Dataprep

VariableTypeRequiredDefaultDescription
DATAPREP_CHUNK_SIZEnumberno500Token/char count per chunk (Python-side fallback when no per-format override matches)
DATAPREP_CHUNK_SIZE_PDFnumberno500PDF chunk size
DATAPREP_CHUNK_SIZE_DOCXnumberno1000DOCX chunk size (1000+ recommended)
DATAPREP_CHUNK_SIZE_XLSXnumberno1500XLSX chunk size (1500+ recommended to avoid splitting rows)
DATAPREP_CHUNK_SIZE_PPTXnumberno500PPTX chunk size
DATAPREP_CHUNK_SIZE_HTMLnumberno500HTML chunk size
DATAPREP_CHUNK_SIZE_TXTnumberno500TXT chunk size
DATAPREP_CHUNK_SIZE_MDnumberno500Markdown chunk size
DATAPREP_CHUNK_OVERLAPnumberno50Overlap between chunks
DATAPREP_MAX_CONCURRENT_BATCHESnumberno20Concurrent LLM label calls (was 5 in legacy configs)
DOCLING_DEVICEenumnocudacuda or cpu — CUDA is faster
DATAPREP_COMPONENT_NAMEstringnoGENIE_DATAPREP_ARANGODBDataprep component name
DOCUMENT_REPOSITORY_URLstringnohttp://document-repository:3001Doc-repo internal URL
BACKEND_SERVICE_URLstringnohttp://backend:3000Backend URL (for hierarchy fetch)
LABELING_STRATEGYenumnollmllm / embedding / bm25
EMBEDDING_LABEL_THRESHOLDnumberno0.75Threshold for embedding-based labeling
BM25_LABEL_THRESHOLDnumberno2.00Threshold for BM25 labeling
CONTENT_EXTRACTION_METHODenumnodocling (compose) / opea (Python code)opea or docling (compose wins at runtime; set in .env to override)
LABEL_SELECTOR_SYSTEM_PROMPTstringno(built-in)LLM labeling rules
CONTEXTUAL_RETRIEVAL_ENABLEDboolnotruePrepend LLM doc-context prefix to each chunk
CONTEXTUAL_STRATEGYenumnodoc_levelper_chunk or doc_level (compose default doc_level; Python code default per_chunk — compose wins at runtime; set in .env to override)
CONTEXTUAL_RETRIEVAL_PROMPTstringno(built-in)Per-chunk context prompt ({document_context} placeholder)
MULTI_TURN_BLEND_ENABLEDboolnofalseMulti-turn vector-space blending
MULTI_TURN_BLEND_ALPHAnumberno0.7Query weight α in V = α·EQ + (1-α)·EH
MULTI_TURN_HISTORY_TURNSnumberno1Prior turns blended into history embedding
DATAPREP_CONTEXTUAL_MODELstringno(empty)Model for context generation (empty = VLLM_LLM_MODEL_ID); must support guided JSON
DATAPREP_CONTEXTUAL_DOC_BUDGETnumberno6000 (compose) / 100000 (Python code)Max chars of doc text fed to context LLM (~1500 tokens); <=0 disables truncation (sibling _DOC_LEVEL variant defaults to 100000). Compose wins at runtime; set in .env to override
DATAPREP_CONTEXTUAL_MAX_TOKENSnumberno512Max output tokens for context-gen LLM (was 200, truncated under load)

Retriever

VariableTypeRequiredDefaultDescription
RETRIEVER_COMPONENT_NAMEstringnoGENIE_RETRIEVER_ARANGODBRetriever component name
RETRIEVER_ARANGO_SEARCH_STARTstringnochunk (compose) / node (Python code)Graph traversal starting point (chunk/node/edge) — compose wins at runtime
RETRIEVER_ARANGO_SEARCH_MODEenumnovectorvector / hybrid (hybrid is controlled separately by RETRIEVER_HYBRID_RETRIEVAL_ENABLED)
RETRIEVER_HYBRID_RETRIEVAL_ENABLEDboolnotrueMaster switch for hybrid BM25+dense fusion
RETRIEVER_ARANGO_TRAVERSAL_ENABLEDboolnotrue (compose) / false (Python code)Enable graph traversal — compose wins at runtime
RETRIEVER_ARANGO_TRAVERSAL_MAX_DEPTHnumberno2 (compose) / 1 (Python code)Max graph traversal depth — compose wins at runtime
RETRIEVER_ARANGO_TRAVERSAL_MAX_RETURNEDnumberno5 (compose) / 3 (Python code)Max items returned by traversal — compose wins at runtime
RETRIEVER_ARANGO_TRAVERSAL_SCORE_THRESHOLDnumberno0.7 (compose) / 0.5 (Python code)Min score to keep traversal results — compose wins at runtime
RETRIEVER_ARANGO_TRAVERSAL_CONCURRENT_BATCHESnumberno10 (compose) / 1 (Python code)Concurrent traversal batches — compose wins at runtime
RETRIEVER_ARANGO_DISTANCE_STRATEGYstringnoCOSINEDistance metric for vector search
RETRIEVER_ARANGO_NUM_CENTROIDSnumberno1Vector-search centroids
RETRIEVER_ARANGO_USE_APPROX_SEARCHboolnofalseUse ANN search
RETRIEVER_ARANGO_Knumberno20Top chunks returned to reranker
RETRIEVER_ARANGO_FETCH_Knumberno30Candidate chunks scored before filtering
RETRIEVER_ARANGO_SCORE_THRESHOLDnumberno0.2Min similarity score
RETRIEVER_ARANGO_DISTANCE_THRESHOLDnumberno1Max distance
RETRIEVER_ARANGO_LAMBDA_MULTnumberno0.5MMR diversity factor (0 = relevance-only, 1 = max diversity)
RETRIEVER_ARANGO_FILTER_STRATEGYenumnoOROR or AND for label filters
RETRIEVER_SUMMARIZER_ENABLEDboolnofalseLLM-summarize retrieved chunks (latency-heavy)

For tuning guidance see RAG → Retriever Configuration and the Retriever overview in the source code.

Network & external services

VariableTypeRequiredDefaultDescription
NGINX_PUBLIC_DOMAINstringnolocalhostPublic FQDN / IP for nginx
NGINX_HTTP_PORTnumberno80HTTP port
NGINX_HTTPS_PORTnumberno443HTTPS port
NGINX_FRONTEND_HOSTstringnofrontendInternal frontend host
NGINX_FRONTEND_PORTnumberno8090Internal frontend port
KONG_PROXY_HOSTstringnokongKong proxy host
HUGGING_FACE_HUB_TOKENsecretyes (with GPU)<set-me>HF token for model pulls
VLLM_API_KEYsecretyes (with remote GPU)<set-me>Bearer token for remote GPU node
DEPLOY_OPEAenumno10 to disable all OPEA services; 1 (default) keeps them
ENABLE_OBSERVABILITYenumno00 / 1 — observability stack on/off
CERTBOT_EMAILstringno(unset)Let’s Encrypt account email
CERTBOT_REPLICASnumberno0Certbot replicas
CERTBOT_STAGINGboolnofalseUse Let’s Encrypt staging
GPU_NODE_HOSTstringno(unset)Remote GPU node host (deploys only orchestrators when set)
GPU_MODEL_REPLICASnumberno1 (cascades from DEPLOY_OPEA, default 1)Replicas for GPU model containers
GPU_PUBLIC_DOMAINstringno(unset)Public FQDN of remote GPU node
VLLM_ENDPOINTstringnohttp://vllm:8000 (compose-internal)vLLM endpoint override; for remote GPU set VLLM_ENDPOINT=https://${GPU_NODE_HOST}/llm in .env (no automatic override)
VLLM_TRANSLATION_ENDPOINTstringnohttp://vllm-translation-guardrail:9031 (compose-internal)vLLM translation endpoint; for remote GPU set VLLM_TRANSLATION_ENDPOINT=https://${GPU_NODE_HOST}/translation in .env (compose does NOT auto-substitute)
EMBEDDING_SERVICE_URLstringnohttp://tei:80 (compose-internal)Embedding service URL; for remote GPU set EMBEDDING_SERVICE_URL=https://${GPU_NODE_HOST}/embed in .env (compose does NOT auto-substitute)
RERANKER_SERVICE_URLstringnohttp://tei_reranker:80 (compose-internal)Reranker service URL; for remote GPU set RERANKER_SERVICE_URL=https://${GPU_NODE_HOST}/rerank in .env (compose does NOT auto-substitute)
DOCLING_ENDPOINTstringno(empty, uses in-process docling)Remote docling-serve endpoint for document extraction; set to https://${GPU_NODE_HOST}/docling when using remote GPU
DOCLING_ENDPOINT_TIMEOUTnumberno120HTTP timeout (seconds) for remote docling-serve calls
OPEA_SSL_SKIP_VERIFYboolno0Skip SSL verification for OPEA Python services
KEYCLOAK_SSL_SKIP_VERIFYboolno0Skip SSL verification for dataprep’s Keycloak client
NODE_TLS_REJECT_UNAUTHORIZEDboolno1Node.js TLS verification (0 for self-signed dev certs)

Keycloak

VariableTypeRequiredDefaultDescription
KEYCLOAK_URLstringnohttps://localhost/authPublic Keycloak URL
KEYCLOAK_REALMstringnogenieRealm name
KEYCLOAK_CLIENT_IDstringnogenie-appOIDC client ID
KEYCLOAK_CLIENT_SECRETsecretyes<set-me>OIDC client secret
KEYCLOAK_PROXY_CLIENT_SECRETsecretyes<set-me>Service-account secret for the admin API proxy
KC_DATAPREP_CLIENT_IDstringnodataprep-service-clientService-account client ID used by dataprep (client_credentials grant for service-to-service auth)
KC_DATAPREP_CLIENT_SECRETsecretyes<set-me>Service-account secret for dataprep → doc-repo / backend API calls
KC_MOBILE_CLIENT_IDstringnogenie-mobile-<institution>Public OIDC client ID for the Flutter mobile app (PKCE, no secret — RFC 8252). Must match the Flutter flavor’s clientId
KC_MOBILE_REDIRECT_SCHEMEstringnocom.<institution>.genieaiCustom URL scheme for mobile OIDC callback (must match Android appAuthRedirectScheme, iOS APP_AUTH_REDIRECT_SCHEME, and the Flutter flavor’s redirectScheme — mismatch causes silent auth failure)
KEYCLOAK_ADMIN_PASSWORDsecretyes<set-me>Master admin console password
KEYCLOAK_DB_PASSWORDsecretyes<set-me>Keycloak dedicated PG user password
KEYCLOAK_ADDITIONAL_REALMSstringno(unset)JSON array of additional realms
KEYCLOAK_REGISTRATION_ENABLEDboolnotrueAllow self-registration
KEYCLOAK_VERIFY_EMAILboolnotrueRequire email verification
KEYCLOAK_RESET_PASSWORDboolnotrueAllow password reset
KEYCLOAK_LOGIN_WITH_EMAILboolnotrueAllow login by email
KEYCLOAK_DUPLICATE_EMAILSboolnofalseAllow duplicate emails across users
KEYCLOAK_BRUTE_FORCEboolnotrueEnable brute-force protection
KEYCLOAK_PASSWORD_POLICYstringnolength(12) and upperCase(1) and lowerCase(1) and digits(1) and specialChars(1)Password complexity rules
KEYCLOAK_THEMEstringnogenieLogin theme
KEYCLOAK_I18N_ENABLEDboolnotrueEnable login-page i18n
KEYCLOAK_LOCALEstringno_unset (fallback: en from realm)Default login locale. If set, overrides the realm defaultLocale. Commented in env — uncomment to change.
KEYCLOAK_SUPPORTED_LOCALESstringno["ar","de","en","es","fr","pt","ru","th","zh-Hans"]JSON array of supported login locales. See Restrict active locales for the canonical reference.
KEYCLOAK_ACCESS_TOKEN_LIFESPANnumberno300Access-token TTL (seconds)
GENIE_ADMIN_EMAILstringno(unset)Initial admin email
GENIE_ADMIN_USERNAMEstringnogenie-adminInitial admin username
GENIE_ADMIN_PASSWORDsecretyes<set-me>Initial admin password

Observability (optional — ENABLE_OBSERVABILITY=1)

VariableTypeRequiredDefaultDescription
OTEL_EXPORTER_OTLP_ENDPOINTstringnohttp://otel-collector:4318OTLP collector base URL
OTEL_TRACES_SAMPLER_RATEnumberno100.0Trace sampling percentage
GRAFANA_ADMIN_USERstringnoadminGrafana admin user
GRAFANA_ADMIN_PASSWORDsecretyes<set-me>Grafana admin password
GRAFANA_ALERT_EMAILstringno(unset)Alert notification email (reserved — not yet wired into contact points)
GRAFANA_PORTnumberno3002Host port for Grafana
VICTORIAMETRICS_RETENTIONstringno30dMetric retention period
VICTORIALOGS_RETENTIONstringno30dLog retention period
VICTORIATRACES_RETENTIONstringno30dTrace retention period
KONG_TRACING_INSTRUMENTATIONSstringnorequestKong tracing instrumentations
KONG_TRACING_SAMPLING_RATEnumberno1.0Kong trace sampling rate 0.0–1.0
KC_GRAFANA_CLIENT_IDstringnografanaGrafana OIDC client ID
KC_GRAFANA_CLIENT_SECRETsecretyes<set-me>Grafana OIDC client secret

Step 7: Initialize Swarm and deploy

flowchart LR
    A[Step 6: edit .env] --> B[docker swarm init]
    B --> C[Label nodes<br/>gateway / genieai / gpu]
    C --> D[docker compose config<br/>resolves $VAR from .env]
    D --> E{Profiles?}
    E -->|opea| F[compose config picks up OPEA]
    E -->|gpu-models| G[compose config picks up GPU]
    E -->|observability| H[compose config picks up obs]
    F --> I[docker stack deploy]
    G --> I
    H --> I
    I --> J[Stack healthy?]
    J -->|no| K[Step 8 troubleshoot]
    J -->|yes| L[Step 9 KB population]

7a. Initialize Swarm

docker swarm init
docker node update --label-add gateway=true $(hostname)
docker node update --label-add genieai=true $(hostname)
docker node update --label-add gpu=true $(hostname)

For multi-node Swarm see Docker Swarm Setup → Step 2.

7b. Pre-resolve env into a flat YAML

Important: docker stack deploy does not substitute ${VAR} references from environment variables. Always run docker compose config first to produce a flat YAML, then deploy the resolved file.

set -a && source .env && set +a
docker compose config > docker-compose.resolved.yaml

With GPU-specific overrides (T4):

set -a && source .env && source env.t4 && set +a
docker compose config > docker-compose.resolved.yaml

7c. Deploy the stack

docker stack deploy -c docker-compose.resolved.yaml genieai

For a docker compose up single-host dev workflow see Docker Compose Setup → Step 6.

Step 8: Verify deployment is healthy

# Services should be 1/1 with (healthy)
docker service ls

# Kong configured
docker service logs genieai_kong-config --tail 20
# Look for: "Configuration restored successfully"

# Keycloak realm applied
docker service logs genieai_keycloak-config --tail 10

# Smoke tests
curl -sk https://localhost/api/health
curl -sk https://localhost/

GPU stack confirmation (with --profile opea --profile gpu-models):

docker service logs genieai_vllm -f | grep 'Application startup complete'
curl -sk https://localhost/api/health | python3 -m json.tool

Step 9: Knowledge-base population

The framework is empty until you ingest documents. The pipeline is:

  1. Create the label taxonomy (categories + services) in the Admin Dashboard → Knowledge Hierarchy tab. For design principles see Labelling Taxonomy.
  2. Upload documents through the Admin Dashboard → Document Management tab, or via the document-repository upload API. Supported formats and known issues are documented in Content Guidance.
  3. Dataprep ingests each document: extracts text, splits into chunks, runs LLM-based labeling (or embedding / BM25 based on LABELING_STRATEGY), and stores everything in ArangoDB. Progress and failures land in the ingestion_log collection — visible in the Admin Dashboard.
  4. Track per-chunk progress with the Ingestion Log (see also Ingestion pipeline).

Step 10: First-time user accounts

The genie-admin user is provisioned automatically during deployment by configs/keycloak/genie-realm.yaml. No script is required.

  • Admin console: https://<NGINX_PUBLIC_DOMAIN>/auth/admin/ (username admin, password from KEYCLOAK_ADMIN_PASSWORD)
  • GENIE realm admin: username genie-admin (configurable via GENIE_ADMIN_USERNAME), password from GENIE_ADMIN_PASSWORD, has the admin realm role

To change the admin password, log in to the Keycloak admin console, switch to the genie realm, then Users → genie-admin → Credentials → Set password.

For full user-management instructions (CRUD, role assignment, security considerations) see Keycloak Admin Operations Guide.

Step 11: Common post-deploy configuration

11a. NGINX

You do not need to configure NGINX manually — it auto-renders from default.conf.template at startup. Common customization knobs:

VariablePurpose
NGINX_PUBLIC_DOMAINPublic FQDN / IP the server is reachable at (drives redirect URIs and CORS allow-list)
NGINX_HTTPS_PORTHTTPS port (default 443); set when running behind a non-standard port
NGINX_HTTP_PORTHTTP port (default 80); set to 0 to disable HTTP entirely
NGINX_FRONTEND_HOST / NGINX_FRONTEND_PORTInternal frontend routing target (rarely changed)

For custom TLS certificates (production / non-Let’s-Encrypt), drop the cert + key into the nginx_secrets Docker volume and restart genieai_nginx. The entrypoint detects the mounted files at startup and falls back to a self-signed cert only if none are mounted. See Security Hardening.

11b. Kong

Kong database migrations run automatically as part of stack deploy. Routes and plugins are applied by the kong-config one-shot service after Kong becomes healthy — no manual configuration is needed for the default routes.

  • Custom routes → add YAML to api-gateway-solution/new-config/ (the restore script picks them up automatically).
  • Custom plugins → enable via the Kong admin API or add to the declarative config alongside routes.
  • Trusted proxies → KONG_TRUSTED_IPS (default 172.16.0.0/12); expand when Kong sits behind an additional reverse proxy.
  • Tracing → KONG_TRACING_INSTRUMENTATIONS and KONG_TRACING_SAMPLING_RATE (observability profile).

For full Kong operations (route CRUD, plugin config, RBAC) see Docker Swarm Setup → Kong trusted IPs.

11c. Keycloak realm

The genie realm (clients, roles, mappers, the genie-admin user) is applied by keycloak-config. Common post-deploy knobs:

VariablePurpose
KEYCLOAK_SUPPORTED_LOCALESJSON array of login-page locales (e.g. ["en","es"]) — see Restrict active locales
KEYCLOAK_PASSWORD_POLICYRealm password complexity rules (default: length(12) + 1 upper/lower/digit/special)
KEYCLOAK_BRUTE_FORCEEnable Keycloak’s built-in brute-force protection (default true)
KEYCLOAK_VERIFY_EMAILRequire email verification on signup (default true)
KEYCLOAK_REGISTRATION_ENABLEDAllow self-registration (default true; set false to invite-only)
KEYCLOAK_ACCESS_TOKEN_LIFESPANAccess-token TTL in seconds (default 300)
GENIE_ADMIN_USERNAME / GENIE_ADMIN_PASSWORDSeeded genie-admin user credentials (change after first login)
KEYCLOAK_ADDITIONAL_REALMSJSON array of additional realms to bootstrap alongside genie

For full user/realm management (CRUD, role assignment, security considerations) see Keycloak Admin Operations Guide. For external IdPs (Google, Microsoft, SAML/OIDC) see External IdP Integration Guide.

11d. Branding & dashboard

To make the deployment look like your institution rather than upstream GENIE.AI, see Branding Customization and Admin dashboard customization to set the per-institution banner, splash image, logo, and dashboard tiles. Both live under the deployment’s flavors/<name>/ directory; see Deployment flavors for the full flavor layout (image overrides, locale whitelist, mobile OIDC client).

Troubleshooting

For environment-specific troubleshooting see:

Common first-deploy failures (deployer-oriented, not environment-specific):

SymptomLikely causeFix
docker stack deploy reports service "x" uses unsupported attributedocker stack deploy does not honor --profile; profiles are evaluated by docker compose config onlyRun docker compose config > docker-compose.resolved.yaml first (see Step 7b), then docker stack deploy -c docker-compose.resolved.yaml genieai
Replicas stay at 0/N after docker stack deployOPEA/AI services gated by DEPLOY_OPEA=0 (compose default in older configs); or replicas: 0 for the GPU services when GPU_MODEL_REPLICAS=0Set DEPLOY_OPEA=1 (default); with remote GPU, keep GPU_MODEL_REPLICAS=0 and set GPU_NODE_HOST so the chatqna-orchestrators reach vLLM/TEI over the network
curl https://localhost/api/health returns 502 / 404NGINX hasn’t rendered default.conf.template, or Kong upstream lacks the /api routedocker service logs genieai_nginx --tail 50 — should show Rendering nginx config from template... followed by Validating nginx configuration... and Starting nginx.... Then docker service logs genieai_kong-config --tail 50 — should show Configuration restored successfully
curl https://localhost/ redirects to Keycloak but login fails with invalid redirect_uriNGINX_PUBLIC_DOMAIN mismatches the URL used to reach the server, or NGINX_HTTPS_PORT is unset on a non-standard portSet NGINX_PUBLIC_DOMAIN and (if not 443) NGINX_HTTPS_PORT in .env, then redeploy. Keycloak valid redirect URIs derive from these
vLLM OOMKilled on first bootVLLM_GPU_UTILIZATION too high or model too large for the GPULower VLLM_GPU_UTILIZATION (compose default 0.55 — see docker-compose.yaml:800; env.t4=0.4, env.rtx6000=0.6); see GPU Deployment for per-GPU settings. Use env.t4 (T4 16 GB) or env.rtx6000 (24 GB) as starting points
Stack deploys cleanly but services crash at startup with Missing *PASSWORD / Missing *SECRET errorsAll *_PASSWORD / *_SECRET values must be set before first deploy. docker compose config does NOT enforce required vars (it silently substitutes empty strings) — failures surface only at container startupGenerate strong values: python3 -c "import secrets; print(secrets.token_urlsafe(32))" and assign to each PASSWORD/SECRET listed in Step 6a. The required secrets are: POSTGRES_PASSWORD, KONG_DB_PASSWORD, ARANGO_PASSWORD, TRANSLATION_CACHE_PASSWORD, KEYCLOAK_ADMIN_PASSWORD, KEYCLOAK_DB_PASSWORD, KEYCLOAK_CLIENT_SECRET, KEYCLOAK_PROXY_CLIENT_SECRET, KC_DATAPREP_CLIENT_SECRET, EMAIL_PASSWORD, GENIE_ADMIN_PASSWORD (and HUGGING_FACE_HUB_TOKEN / VLLM_API_KEY when using GPU)
Step 6c vars show “(unset)” but compose substitutes a default anywayMany VUE_*, CSP_*, CORS_* vars fall back to compose-level defaults (e.g. 'self' http://localhost:3000 …) — leave them unset for local dev, override in .env for productionOverride in .env; see env Section 5 (frontend) and Section 6 (backend) for the full list

Next steps

You now have GENIE.AI running. Continue with: