Skip to content

Installation

The NidanEHR services deploy as a single Docker Compose project from the nidan-docker/ directory. The configuration is managed through a .env file, routing EMR, laboratory, ERP, PACS, integration middleware, and reporting services onto a single private network behind a reverse proxy.

Applies to

The current NidanEHR stack defined by nidan-docker/docker-compose.yml: OpenMRS 2.8.x · OpenELIS-Global 2 · Odoo 19 CE · Orthanc · Kafka 7.5 · Keycloak. Service images and versions are pinned in that file.

Every value on this page is a dummy

The example values below - especially passwords, secrets, and admin credentials - are placeholders for illustration. Generate your own secrets and replace every change-me-* value before deploying. Never commit a real .env.

Prerequisites

  • Docker Engine 24+ and the Docker Compose v2 plugin.
  • ~8 GB RAM free for the full stack; more for production load.
  • The monorepo checked out, so nidan-docker/ sits next to its sibling components.
  • For a build-from-source deploy: the custom OpenMRS OMODs built and copied into nidan-docker/openmrs/custom_modules/ (see Build the OpenMRS image).

Quick start

cd nidan-docker

# 1. Create your environment file from the template
cp env.template .env
#    then edit .env - set domains and replace every secret (see tables below)

# 2. (build-from-source only) build custom OMODs into openmrs/custom_modules/ first
#    then build the images that are built locally
docker-compose build openmrs-backend openmrs-frontend gateway superset

# 3. Start everything
docker-compose up -d

# 4. Watch a service come up
docker-compose logs -f openmrs-backend

When the stack is healthy, the gateway serves everything on one host:

URL (through the gateway) Application
/ Dashboard landing page
/openmrs, /openmrs/spa/ OpenMRS EMR (O3 SPA)
/odoo Odoo ERP
/openelis/ OpenELIS lab UI
/api/OpenELIS-Global/ OpenELIS backend API
/orthanc-container Orthanc PACS
/auth Keycloak
/superset Superset BI

Published host ports

The gateway is the only surface you need in production. The other published ports exist for direct or debug access and can be closed off behind the gateway/firewall.

Host port Service Purpose
80, 443, 8443 gateway HTTP, HTTPS, and the OpenELIS-only TLS port
3307 openmrs-db MariaDB (maps to container 3306)
8069 odoo Odoo direct access
8042, 4242 orthanc DICOMweb/HTTP and DICOM
15432 openelis-db OpenELIS PostgreSQL (container 5432)
8083 openelis OpenELIS backend (container 8080)
8085 openelis-frontend OpenELIS UI (container 80)
8088 superset Superset direct access (remove in production)

Build the OpenMRS image

Custom OMODs are deliberately kept out of git. Build and copy them before building the backend image, in dependency order:

# from the repo root, for each module:
cd openmrs-backend/openmrs-module-<name>
mvn package -DskipTests
cp omod/target/*.omod ../../nidan-docker/openmrs/custom_modules/

Build order matters: fhir2medication-administrationipd. Building the image without copying the OMODs produces a working distro that is silently missing functionality.


Environment Configuration Reference

The tables below define variables from env.template grouped by application. Hostnames such as openmrs-db or odoo resolve internally on the nidan-network bridge and must not be altered unless the corresponding container names change.

Gateway & TLS

Variable Example value Description
GATEWAY_IMAGE trigonaltechnology/gateway:latest Nginx gateway image to pull/run.
GATEWAY_DOMAIN ehr.example.org Public hostname the gateway serves.
DASHBOARD_ODOO_URL https://ehr.example.org:8069 Odoo link shown on the dashboard card.
CERTBOT_EMAIL ops@example.org Contact email for Let's Encrypt registration.
CERTBOT_DOMAINS ehr.example.org Comma-separated domains to request certs for.
SSL_TRUSTSTORE_PATH /certs/truststore.p12 Optional truststore for outbound HTTPS/FHIR clients.
SSL_TRUSTSTORE_PASSWORD change-me-truststore Password for the truststore above.
SSL_KEYSTORE_PATH /certs/keystore.p12 Optional keystore path.
SSL_KEYSTORE_PASSWORD change-me-keystore Password for the keystore above.

OpenMRS (EMR)

OpenMRS owns patients, encounters, and orders. The active Compose file runs its database on MariaDB with row-based binlog enabled (Debezium/CIS reads it). The nidan-cis middleware authenticates to OpenMRS as a dedicated sync account.

OpenMRS - database & app

Variable Example value Description
OPENMRS_DB_NAME openmrs OpenMRS schema/database name.
OPENMRS_DB_USER openmrs Application DB user.
OPENMRS_DB_PASSWORD change-me-omrs-db Password for the app DB user.
OPENMRS_DB_ROOT_PASSWORD change-me-omrs-root MariaDB root password (also used by Debezium).
OPENMRS_DB_HOST openmrs-db DB service hostname on the network.
OPENMRS_DB_PORT 3306 Container-internal DB port (host-published as 3307).
POSTGRES_MAX_SLOT_WAL_KEEP_SIZE 1GB WAL retention cap (only used if the Postgres profile is enabled).
OMRS_DEBUG false Enable verbose OpenMRS logging.

OpenMRS - REST / sync account

Variable Example value Description
OPENMRS_USERNAME nidan-sync Account CIS uses to read/write OpenMRS; keep equal to NIDAN_SYNC_USERNAME.
OPENMRS_PASSWORD change-me-sync-pass Password for the sync account; keep equal to NIDAN_SYNC_PASSWORD.
OPENMRS_ADMIN_USERNAME admin Real admin, used by CIS only at startup to create the sync account.
OPENMRS_ADMIN_PASSWORD change-me-omrs-admin Password for the bootstrap admin.
NIDAN_SYNC_USERNAME nidan-sync Shared sync service account the middleware provisions in OpenMRS/OpenELIS.
NIDAN_SYNC_PASSWORD change-me-sync-pass Password for the shared sync account. Change before deploy.
OPENMRS_IDENTIFIER_TYPE_UUID c0e1d2f3-…-1a2b3c4d5e6f Patient identifier type CIS assigns.
OPENMRS_DEFAULT_LOCATION_UUID 44c3efb0-…-1f756a03c0a1 Default location for synced records.
OPENMRS_FHIR_EXTENSION_URL http://fhir.openmrs.org/ext/patient/identifier#location FHIR extension URL for identifier location.

OpenMRS - order type UUIDs

CIS resolves these to internal order_type_ids at startup; they come from the Initializer ordertypes.csv.

Variable Example value Description
OPENMRS_ORDER_TYPE_UUID_DRUG 131168f4-…-000c29c2a5d7 Drug order type.
OPENMRS_ORDER_TYPE_UUID_LAB 52a447d3-…-50e549534c5e Lab order type.
OPENMRS_ORDER_TYPE_UUID_RADIOLOGY c19c8e82-…-3f09890b2db3 Radiology order type.
OPENMRS_ORDER_TYPE_UUID_PROCEDURE 4237a01f-…-96d6e590aa33 Procedure order type.
OPENMRS_ORDER_TYPE_UUID_MEDICAL_SUPPLY dab3ab30-…-8332a0831b49 Medical supply order type.
OPENMRS_ORDER_TYPE_UUID_BED e8c4fd91-…-1a2b3c4d5e6f Bed order type (optional until CIS handles bed orders).

Orthanc (PACS)

Variable Example value Description
ORTHANC_DB_NAME orthanc Orthanc PostgreSQL database name.
ORTHANC_DB_USER orthanc Orthanc DB user.
ORTHANC_DB_PASSWORD change-me-orthanc-db Orthanc DB password.
ORTHANC_DB_HOST orthanc-db Orthanc DB service hostname.
ORTHANC_USERNAME nidan HTTP Basic user for the Orthanc UI / CIS.
ORTHANC_PASSWORD change-me-orthanc HTTP Basic password.
ORTHANC_DICOM_UID_ROOT 1.2.840.10008 DICOM UID root for generated instances.

OpenELIS (Lab)

Variable Example value Description
OPENELIS_DOMAIN ehr.example.org Hostname OpenELIS serves under.
OPENELIS_DB_NAME clinlims OpenELIS PostgreSQL database name.
OPENELIS_DB_USER clinlims OpenELIS DB user.
OPENELIS_DB_PASSWORD change-me-elis-db OpenELIS DB password.
OPENELIS_DEFAULT_ADMIN_PASSWORD change-me-elis-admin Initial OpenELIS admin password.
OPENELIS_TZ Asia/Kathmandu Container timezone.
OPENELIS_ENABLED true Whether CIS talks to OpenELIS.
OPENELIS_BASE_URL http://openelis:8080/OpenELIS-Global/rest OpenELIS REST base URL CIS calls.
OPENELIS_USERNAME admin OpenELIS REST user for CIS.
OPENELIS_PASSWORD change-me-elis-admin OpenELIS REST password.
CIS_BASE_URL http://nidan-cis:8081 CIS URL OpenELIS calls back for sync.
OPENELIS_MIDDLEWARE_TEST_SYNC_ENABLED false Sync test catalog OpenELIS→middleware.
OPENELIS_MIDDLEWARE_RESULT_SYNC_ENABLED true Push lab results back through the middleware.
OPENELIS_NIDAN_TESTORDER_ENABLED true Accept test orders from the middleware.
OPENELIS_MIDDLEWARE_SYNC_SECRET change-me-elis-sync Shared secret for OpenELIS↔CIS sync calls.
OPENELIS_NIDAN_PAYWALL_ENABLED true Gate result release on Odoo billing.
NIDANCORE_ODOO_URL http://odoo:8069 Odoo URL the paywall checks.
OPENELIS_NIDAN_PAYWALL_INSURANCE_BYPASS true Let insured patients bypass the paywall.

Odoo (ERP)

Odoo owns billing, pharmacy, inventory, and POS. Note Odoo has two DB credential sets: the application DB (ODOO_DB_*) and the PostgreSQL superuser (ODOO_POSTGRES_*).

Variable Example value Description
ODOO_DB_NAME nidan Odoo application database name.
ODOO_DB_USER nidan Odoo application DB user.
ODOO_DB_PASSWORD change-me-odoo-db Odoo application DB password.
ODOO_POSTGRES_USER odoo PostgreSQL superuser.
ODOO_POSTGRES_PASSWORD change-me-odoo-pg PostgreSQL superuser password.
ODOO_POSTGRES_DB postgres Bootstrap/maintenance database.
ODOO_DB_HOST odoo-db Odoo DB service hostname.
ODOO_DB_PORT 5432 Odoo DB port.
ODOO_ADMIN_EMAIL admin@example.org Odoo master/admin login.
ODOO_ADMIN_PASSWORD change-me-odoo-admin Odoo admin password.
ODOO_WEB_BASE_URL https://ehr.example.org/odoo Public base URL Odoo generates links with.
ODOO_WEB_BASE_URL_FREEZE True Prevent Odoo from auto-overwriting the base URL.
ODOO_IMAGE trigonaltechnology/nidan_odoo_pro:stable Odoo image; use the Pro image to bake closed-source addons.
ODOO_EXTRA_ADDONS_HOST_PATH ../odoo_19_addons Dev-only: host path for open-source addons.
ODOO_PRIVATE_ADDONS_HOST_PATH ../nidan_odoo_extra_addons Dev-only: host path for private addons.
ODOO_USERNAME admin Odoo user OIS uses for JSON-RPC.
ODOO_PASSWORD change-me-odoo-admin Password for the OIS JSON-RPC user.

Keycloak (identity)

Variable Example value Description
KEYCLOAK_DB_NAME keycloak Keycloak database name.
KEYCLOAK_DB_USER keycloak Keycloak DB user.
KEYCLOAK_DB_PASSWORD change-me-kc-db Keycloak DB password.
KEYCLOAK_ADMIN_USER admin Keycloak admin console user.
KEYCLOAK_ADMIN_PASSWORD change-me-kc-admin Keycloak admin password.
KEYCLOAK_RELATIVE_PATH /auth Context path the gateway routes to Keycloak.

Middleware database (CIS + OIS)

Variable Example value Description
INTEGRATION_DB_NAME nidan_integration Integration state database (CIS/OIS, Debezium offsets).
INTEGRATION_DB_USER nidan Integration DB user.
INTEGRATION_DB_PASSWORD change-me-int-db Integration DB password.
INTEGRATION_DB_HOST nidan-integration-db Integration DB hostname.
INTEGRATION_DB_PORT 5432 Integration DB port.
MANAGEMENT_HEALTH_REDIS_ENABLED false Include Redis in CIS/OIS health (set true only when Redis is deployed).

Kafka & ZooKeeper

Variable Example value Description
ZOOKEEPER_CLIENT_PORT 2181 ZooKeeper client port.
ZOOKEEPER_TICK_TIME 2000 ZooKeeper tick (ms).
KAFKA_BROKER_ID 1 Broker ID.
KAFKA_PORT 9092 Broker listener port.
KAFKA_ZOOKEEPER_CONNECT nidan-zookeeper:2181 ZooKeeper connection string.
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR 1 Offsets topic replication (1 for single broker).
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR 1 Txn state log replication.
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR 1 Minimum in-sync replicas for txn log.
KAFKA_MIN_INSYNC_REPLICAS 1 Minimum in-sync replicas.

CIS - Clinical Integration Service

Variable Example value Description
NIDAN_CIS_IMAGE trigonaltechnology/nidan-cis:latest CIS image (or nidan-cis:local for a local build).
CIS_PORT 8081 CIS HTTP port.
CIS_KAFKA_GROUP_ID nidan-cis Kafka consumer group for CIS.
OPENMRS_ENABLED true Enable the OpenMRS source.
OPENMRS_BASE_URL http://openmrs-backend:8080/openmrs OpenMRS REST base URL.
ORTHANC_ENABLED true Enable the Orthanc/radiology flow.
ORTHANC_BASE_URL http://orthanc:8042 Orthanc base URL.
ORTHANC_WORKLIST_DIR /var/lib/orthanc/worklists Where CIS writes MWL .wl files (mounted into Orthanc).
DICOM_TYPE orthanc DICOM backend selector.
INTEGRATION_SOURCE_SYSTEM CIS This service's source-system tag.
INTEGRATION_SKIP_SOURCE_SYSTEMS OPENMRS Source systems whose own echoes CIS ignores (loop prevention).
RADIOLOGY_ACCESSION_PREFIX RAD- Prefix for radiology accession numbers.
RADIOLOGY_PROCEDURE_CODE_PREFIX RAD- Prefix for radiology procedure codes.
INTEGRATION_FLOW_RADIOLOGY_MWL_ENABLED true Toggle the radiology MWL workflow.
INTEGRATION_FLOW_RADIOLOGY_POS_ENABLED true Toggle radiology POS (Odoo) workflow.
INTEGRATION_FLOW_LAB_OPENELIS_ENABLED true Toggle lab→OpenELIS workflow.
INTEGRATION_FLOW_LAB_POS_ENABLED true Toggle lab POS workflow.
DEBEZIUM_ENABLED true Enable embedded Debezium CDC from OpenMRS.
DEBEZIUM_DB_USER root DB user Debezium reads the binlog as.
DEBEZIUM_DB_PASSWORD change-me-omrs-root Password for the Debezium DB user.
DEBEZIUM_TABLE_INCLUDE_LIST openmrs.visit,openmrs.orders,… Tables Debezium captures.
INTEGRATION_KAFKA_RETRY_ATTEMPTS 5 Kafka retry attempts before dead-lettering.
INTEGRATION_KAFKA_RETRY_INITIAL_DELAY 5s Initial retry backoff.
INTEGRATION_KAFKA_RETRY_MAX_DELAY 10m Maximum retry backoff.

OIS - Order Integration Service

Variable Example value Description
NIDAN_OIS_IMAGE trigonaltechnology/nidan-ois:latest OIS image (or nidan-ois:local).
OIS_PORT 8082 OIS HTTP port.
OIS_KAFKA_GROUP_ID nidan-ois Kafka consumer group for OIS.
ODOO_BASE_URL http://odoo:8069 Odoo base URL for JSON-RPC.
SKIP_SOURCE_SYSTEMS_FOR_ODOO ODOO Source systems OIS suppresses to Odoo (loop prevention).
NIDAN_OIS_URL http://nidan-ois:8082 OIS URL the Odoo module calls.
NIDAN_OIS_SECRET change-me-ois-secret Shared secret between Odoo and OIS.

Keep the shared Odoo/OIS secrets aligned

NIDAN_OIS_SECRET, NIDAN_ODOO_SECRET, ODOO_NIDAN_SECRET, and OIS_WEBHOOK_SECRET are a set of shared secrets between Odoo and OIS. Set them to the same dummy-replaced value on both sides, or webhooks will be rejected.

DHIS2 / Federal HMIS reporting

Variable Example value Description
DHIS2_APP_PORT 5000 Reporting app port.
DHIS2_SECRET_KEY change-me-long-random-string Flask session secret.
DHIS2_FLASK_ENV production Flask environment.
DHIS2_ADMIN_PASSWORD change-me-dhis2-admin Reporting app admin password.
DHIS2_REPORTER_USERNAME reporter Non-admin reporter login.
DHIS2_REPORTER_PASSWORD change-me-dhis2-reporter Reporter password.
DHIS2_DB_NAME nidan_dhis2 Reporting MySQL database.
DHIS2_DB_USER nidan Reporting DB user.
DHIS2_DB_PASSWORD change-me-dhis2-db Reporting DB password.
DHIS2_DB_ROOT_PASSWORD change-me-dhis2-root Reporting MySQL root password.
DHIS2_DB_HOST nidan-dhis2-db Reporting DB hostname.
DHIS2_DB_PORT 3306 Reporting DB port.
FEDERAL_HMIS_URL https://hmis.gov.np/hmis Federal HMIS endpoint.
FEDERAL_HMIS_USERNAME your-hospital-code Federal HMIS username.
FEDERAL_HMIS_PASSWORD change-me-hmis Federal HMIS password.
FEDERAL_HMIS_ORG_UNIT aBcD1234XyZ Federal HMIS org-unit UID.
PROVINCIAL_DHIS2_URL https://dhis2.province.example/ Optional provincial DHIS2 endpoint.
PROVINCIAL_DHIS2_USERNAME province-user Provincial DHIS2 username.
PROVINCIAL_DHIS2_PASSWORD change-me-prov Provincial DHIS2 password.

Superset (BI)

Superset reuses the OPENMRS_DB_*, OPENELIS_DB_*, and ODOO_DB_* values above to seed its database connections.

Variable Example value Description
SUPERSET_SECRET_KEY change-me-long-random-string Superset session secret.
SUPERSET_ADMIN_USERNAME admin Superset admin user.
SUPERSET_ADMIN_PASSWORD change-me-superset-admin Superset admin password.
SUPERSET_LOAD_EXAMPLES no Whether to load Superset example dashboards.
SUPERSET_IMAGE trigonaltechnology/superset:latest Superset image.

Verify the deployment

docker-compose ps                 # all services Up / healthy
docker-compose logs -f gateway    # confirm routing and TLS

Then open https://<GATEWAY_DOMAIN>/ and sign in to each module with the credentials you set.

Database engines per system

In the current Compose file the databases are: OpenMRS → MariaDB 10.11; OpenELIS, Odoo, Orthanc, and the integration store → PostgreSQL; DHIS2 reporting → MySQL 8. A PostgreSQL option for OpenMRS exists in the Compose file but is commented out behind an openmrs-postgres profile.