Skip to Content
DocsRecipesSet up an instance of O3

Setting up an instance of O3

This guide is intended for developers who want to set up an instance of O3. Broadly speaking, there are two approaches for setting up an instance of O3:

  • Using the OpenMRS SDK
  • Using Docker

Using the OpenMRS SDK

ℹ️

You might want to use the SDK if:

  • You already have the SDK, Maven and a Java environment set up on your machine and are very familiar with these tools.
  • You’re not familiar with Docker or don’t want to use Docker.

Prerequisites

These prerequisites are explained in detail in the SDK wiki .

  • Ensure you have Apache Maven  installed.

  • Ensure you have a MySQL or MariaDB instance supported by the O3 distribution you choose.

  • Use a current LTS JDK supported by that distribution. The current Reference Application Dockerfile builds and runs on Amazon Corretto 21, so Java 21 is the safest starting point for current O3 work.

  • Ensure that your $JAVA_HOME environment variable is set and that it points to the JDK you want the SDK to use. If you have the correct version of Java installed but $JAVA_HOME doesn’t point to it, you could try adding the following alias to your .zshrc file (or .bashrc file if you’re using Bash):

    alias mvn='JAVA_HOME="$(/usr/libexec/java_home -v 21)" mvn'

Step 1

Run the following command to install the latest version of the OpenMRS SDK. If you’ve already installed the SDK, you can skip this step.

mvn org.openmrs.maven.plugins:openmrs-sdk-maven-plugin:setup-sdk

Step 2

Run the following command to setup the SDK:

mvn openmrs-sdk:setup

This command will run a prompt that walks you through choosing:

  • A server ID e.g. o3-distro.
  • The type of server to set up - choose O3 Distribution.
  • What version of O3 to deploy - choose the current Reference Application or the specific O3 release you want to test.
  • Which port to run the server on (defaults to 8080).
  • Whether or not to enable remote debugging (defaults to no debugging)
  • When asked to choose which database to use, choose the option that matches your installed MySQL or MariaDB server.
  • When asked to choose a MySQL database URI, go with the default database URI presented.
  • When asked to specify your database username, specify whatever you chose when setting up your MySQL installation (defaults to root).
  • When asked to enter your database password, enter your database password.
  • Once you’re connected to the database, select the JDK version you’d like to use to run the server (e.g. whatever JAVA_HOME points to).

Step 3

Run the following command to fire up the SDK:

mvn openmrs-sdk:run

Step 4

Navigate to http://localhost:8080/openmrs in your browser. You should expect to see the backend getting set up. Once that completes, you can navigate to http://localhost:8080/openmrs/spa.

Troubleshooting the SDK approach

  • If you’re running into issues, first ensure that Maven, the OpenMRS SDK, Java, and your database version match the O3 distribution you selected.

Using Docker

ℹ️

You might want to use Docker if:

  • You are already familiar with Docker and OpenMRS Docker images.
  • You want to run the reference application’s gateway, frontend, backend, and database containers together.
  • You’re working on a deployment that will run Docker containers in production (generally cloud-based or SaaS offerings).
  • You want to set up a fresh instance of O3 (i.e. an instance with a brand new database and not one set up on top of your existing database).
  • You don’t want to go through the hassle of setting up a Java environment and managing multiple dependencies.

Prerequisites

Use the following steps to set up a fresh instance of O3 on your machine using Docker:

Step 1

Clone the distro-referenceapplication  repository.

Step 2

Launch Docker Desktop  or Docker Compose (v2) .

Step 3

From the cloned repository, start the default QA-tagged images:

docker compose -f docker-compose.yml up -d

The reference application compose file defaults TAG to qa, which tracks the current QA images and is convenient for local evaluation. For reproducible testing, fetch the repository tags and run a fixed release tag instead:

git fetch --tags git tag --sort=-v:refname | head TAG=<release-tag> docker compose -f docker-compose.yml up -d

This command does the following:

  • TAG=<release-tag>: Sets the Docker image tag for the gateway, frontend, backend, and related images.
  • docker compose: Runs Docker Compose v2.
  • -f docker-compose.yml: Uses only the base Compose file, so Docker Compose runs published images instead of the local build contexts from docker-compose.override.yml.
  • up -d: Starts the services defined in the Compose file in detached mode.

Step 4

At this point, the backend setup script should be running. During first boot, http://localhost/openmrs may redirect you to the initial setup page at http://localhost/openmrs/initialsetup. This setup will take a few minutes to complete. The O3 frontend is served at http://localhost/openmrs/spa; http://localhost/openmrs is the backend and legacy UI path.

Use the OpenMRS health endpoint to check whether the backend is ready:

curl -f http://localhost/openmrs/health/started

Alternatively, you can run this script in your terminal to check whether the backend is up and running.

while [[ "$(curl -s -o /dev/null -w '%{http_code}' http://localhost/openmrs/health/started)" != "200" ]]; do sleep 10; done

This script will check the status of the server every 10 seconds until the server is up and running.

Once the server is up and running, visit http://localhost/openmrs/spa and you’ll be redirected to the login page. That’s it! You should now have a running instance of O3.

Step 5 (optional)

If you want to run the dockerized build against an existing O2 database, point the backend container at that database instead of starting the bundled db service. See this section below for instructions.

Running an O3 Docker image on top of an existing database

To run the O3 Docker image on top of an existing database, do the following:

Step 1

Working from the standard Docker compose file , remove the db service, remove the db-data volume, and point the backend service at your existing database host. The result should look like this:

docker-compose.yml
services: gateway: image: openmrs/openmrs-reference-application-3-gateway:${TAG:-qa} restart: "unless-stopped" depends_on: - frontend - backend ports: - "80:80" frontend: image: openmrs/openmrs-reference-application-3-frontend:${TAG:-qa} restart: "unless-stopped" environment: SPA_PATH: /openmrs/spa API_URL: /openmrs SPA_CONFIG_URLS: /openmrs/spa/config-core_demo.json SPA_DEFAULT_LOCALE: healthcheck: test: ["CMD", "curl", "-f", "http://localhost/"] timeout: 5s depends_on: - backend backend: image: openmrs/openmrs-reference-application-3-backend:${TAG:-qa} restart: "unless-stopped" environment: OMRS_CONFIG_MODULE_WEB_ADMIN: "true" OMRS_CONFIG_AUTO_UPDATE_DATABASE: "true" OMRS_CONFIG_CREATE_TABLES: "true" OMRS_CONFIG_CONNECTION_SERVER: host.docker.internal OMRS_CONFIG_CONNECTION_DATABASE: openmrs OMRS_CONFIG_CONNECTION_USERNAME: ${OMRS_DB_USER:-openmrs} OMRS_CONFIG_CONNECTION_PASSWORD: ${OMRS_DB_PASSWORD:-openmrs} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/openmrs"] timeout: 5s volumes: - openmrs-data:/openmrs/data volumes: openmrs-data: ~

Step 2

In the backend service, change the OMRS_CONFIG_CONNECTION_SERVER variable to the hostname of the database server and the OMRS_CONFIG_CONNECTION_DATABASE variable to the name of the existing database. On Docker Desktop, host.docker.internal points from a container to a database running on your host machine; on Linux or a remote database server, use the reachable DNS name or IP address instead.

Step 3

Create a .env file in the same folder with OMRS_DB_USER and OMRS_DB_PASSWORD set to the appropriate values for the existing database.

Step 4

Run docker compose up -d and, assuming everything is filled out correctly, the O3 containers should start against your existing database.

Troubleshooting the Docker approach

  • If you’re running into issues related to the Docker daemon, make sure that the daemon is running correctly.

  • If you’re running into an issue on Windows about your WSL version being too low to support running the dockerized build, follow the directions in the error message to update your WSL version. Once done, make sure to restart Docker Desktop or the Docker daemon.

  • If you’re encountering permission errors after running docker compose up, you might be dealing with orphaned volumes left by a previous Docker Compose run. This is a known issue with Docker volumes. Run the following command to delete all orphaned volumes:

    docker compose down -v --remove-orphans

    This command:

    • Stops the running containers defined in the Docker compose file.
    • Removes the containers.
    • Deletes the networks created by the Docker compose.
    • Deletes the volumes associated with the containers.
    • Removes any orphaned containers (containers that were not defined in the docker-compose.yml but are part of the Docker Compose project).

Updating metadata

Based on your requirements, you might want to customize configurations and metadata like concepts, visit types, encounter types, locations, etc. that gets loaded by the initializer module. When customizing such metadata, build the Docker image locally and use that local image for the changes to be shown in the instance. The reference application repository includes docker-compose.override.yml, which adds local build contexts for the gateway, frontend, and backend services when you run Compose from the cloned source tree.

Step 1: Stop your instance

If your O3 instance is actively running, bring it down by running:

docker compose down

This command stops the current containers without the deletion of your volumes, ensuring the retention of your data.

Step 2: Build the local Docker image

To reflect the updated metadata in your instance, you’ll need to build a local Docker image. Ensure your configuration files follow the accepted conventions for each configuration , as incorrect formats might prevent the metadata from appearing in the instance as expected.

TAG=your-custom-tag docker compose build

Replace your-custom-tag with any unique tag of your choice.

ℹ️

It’s advisable to use a tag that does not match any existing tag on Docker Hub  (such as qa or specific release versions) to avoid conflicts. You could alternatively just run docker compose down && docker compose build && docker compose -f docker-compose.yml up -d.

Step 3: Run the instance with the updated image

Next, start your instance using the locally built image by running:

TAG=your-custom-tag docker compose -f docker-compose.yml up -d

Ensure that the argument passed to TAG variable matches the tag you used in the previous step. This command launches the instance using your locally built image instead of pulling one from Docker Hub.

Step 4: Wait for the instance to spin up

Finally, follow Step 4 of the setup guide and wait for your instance to fully spin up with the updated metadata.

Preparing for production

By default, the RefApp source tree is configured to build the frontend with next tagged versions of frontend modules  and the app shell . This means a local image build uses the latest pre-release packages available. Pre-release versions get published to NPM each time a commit is merged into the main branch, so they are not recommended for production use.

⚠️

In production, pin a tested RefApp Docker image tag and explicit non-preview frontend package versions. The latest NPM tag is stable, but it still moves over time; explicit versions make rebuilds reproducible.

Step 1: Update frontend module versions

Update the versions of the frontend modules in your instance from next to the exact versions you tested by editing the frontend/spa-assemble-config.json file as follows. For more information about this file, see the Configuration overview guide:

frontend/spa-assemble-config.json
{ "frontendModules": { "@openmrs/esm-active-visits-app": "x.y.z", "@openmrs/esm-appointments-app": "x.y.z" // ... other frontend modules } }

This ensures that the application will use the same tested versions of these frontend modules every time you rebuild.

Step 2: Update the app shell version

Update the app shell version in the frontend Dockerfile by changing the value of the APP_SHELL_VERSION argument to the exact version you tested:

frontend/Dockerfile
... ARG APP_SHELL_VERSION=x.y.z ...

This change ensures that the app shell is built from the same tested version as your distribution.

Next steps

Once you’ve set up your O3 instance, there are various things you might want to do, including:

  • Setting up a TLS certificate for your instance. This is important if you’re planning to run your instance in production. You can use a service like Let’s Encrypt  to get a free TLS certificate.

  • Changing the default language of your instance. You can do this by navigating to the Administration section of the legacy OpenMRS UI and changing the default locale.

  • Customizing O3. You can tweak your branding, configure modules, and more. See the Configuration overview guide for details.

  • Ensuring that your modules are working correctly (this is relevant only if you’re setting up O3 on top of an existing database). You can use the Manage modules page in the legacy admin interface to see whether modules are running correctly.

  • Testing various features - try registering a patient and launching their chart. Look out for any console errors or any errors in the UI, You might also want to look out for errors in the browser’s devtools network tab. If you don’t have the fhir module running, you should expect to see problems with rendering the patient banner and most other widgets in the chart because things in the chart depend on a valid patient UUID being available, and the patient object gets fetched via a FHIR endpoint,

  • Thinking about how to set up your forms in O3. New O3 forms are usually JSON form schemas that conform to this standard schema  and are rendered by the O3 React Form Engine. O3 can also render configured HTML Form Entry forms through the Patient Forms app, so conversion is only required when you want to move those forms to the JSON schema and Form Engine workflow. Check out the embedded form builder in O3 for an idea of what this format looks like. The schema editor can allow you to build a new form using a dummy schema scaffold. To learn more about forms in O3, read the Building forms using the O3 form builder recipe.

    ℹ️

    An OpenMRS module exists for converting HTML Form Entry schemas into JSON schemas compatible with the O3 standard schema at https://github.com/openmrs/hfe-o3-form-schema-converter . Currently, work is ongoing to improve the tool. Go through the repo’s README to learn what’s possible. See also the Convert HTML form entry forms to O3 guide.

Last updated on