Deployment guide

EHRbase

Videos

Overview: EHRbase on Ubuntu 24.04 LTS on Azure: overview (watch on YouTube)

Launch and log in: EHRbase on Ubuntu 24.04 LTS on Azure: launch and log in (watch on YouTube)

Deep Dive: EHRbase on Ubuntu 24.04 LTS on Azure: deep dive (watch on YouTube)

Overview

EHRbase is an open-source openEHR Clinical Data Repository: a standards-based backend for storing and querying structured electronic health record data. It implements the openEHR Reference Model and stores clinical compositions against uploaded operational templates. It exposes the official openEHR REST API and the Archetype Query Language (AQL) endpoint, so applications read and write vendor-neutral health data over HTTP and JSON.

This SecureAnyCloud image installs EHRbase 2.34 on the Eclipse Temurin Java 25 runtime it requires, backed by a local PostgreSQL 16 database. EHRbase is a headless API server with no web UI, designed to sit behind your own applications, reverse proxy and identity provider.

EHRbase ships with documented default Basic-auth credentials, and a clinical data repository holds sensitive data. This image is therefore secure by default. On the first boot of every VM, a one-shot service rotates the built-in ehrbase-admin and ehrbase-user passwords to unique per-VM values and rotates the two PostgreSQL role passwords with them. It also disables EHRbase's insecure default profile and recreates the database empty, all before the API accepts traffic.

What you get:

  • EHRbase 2.34 (/usr/local/ehrbase/ehrbase.jar) running as a dedicated non-root ehrbase service user on the Eclipse Temurin JRE 25 runtime
  • The official openEHR REST API, served by the embedded server over HTTP on port 8080 under the /ehrbase context path
  • A local standard PostgreSQL 16 as EHRbase's backing database, pre-bootstrapped with the ehrbase and ehrbase_restricted roles, the ehr/ext schemas and the uuid-ossp extension
  • Automatic Flyway schema creation and migration on first start
  • Secure by default: the ehrbase-admin and ehrbase-user Basic-auth passwords and both PostgreSQL role passwords are rotated per VM on first boot, the insecure default profile is disabled and the default credentials are neutralized
  • Per-VM credentials written to the root-only file /root/ehrbase-credentials.txt with mode 0600, so no two VMs share credentials
  • ehrbase.service and postgresql.service as systemd units, enabled and active
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2ms (2 vCPU / 8 GiB RAM) is the recommended starting point. EHRbase runs a Java virtual machine (embedded Tomcat, Hibernate and Flyway) alongside a local PostgreSQL server, so it benefits from memory headroom.

In the network security group (NSG), allow inbound 22/tcp from your management network. Allow 8080/tcp from the networks that your openEHR API client applications connect from. EHRbase serves plain HTTP on port 8080, so for anything beyond a private network, put it behind a TLS-terminating reverse proxy (see below) and expose that instead.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for EHRbase by SecureAnyCloud, and select Create.

On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22). Then select Review + create and Create.

First-boot initialization takes approximately one to two minutes after the VM starts. EHRbase runs its Flyway database migrations, rotates the Basic-auth and database passwords, and starts the embedded API server.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:ehrbase-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name ehrbase \
  --image sac1647283583153:ehrbase-ubuntu-24-04:default:latest \
  --size Standard_B2ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name ehrbase --port 8080 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

Run the following to check both services:

systemctl is-active postgresql ehrbase
PASS=$(sudo grep '^EHRBASE_USER_PASSWORD=' /root/ehrbase-credentials.txt | cut -d= -f2-)
curl -s -u "ehrbase-user:$PASS" -H 'Accept: application/json' http://127.0.0.1:8080/ehrbase/rest/status

Both services should report active. The authenticated /rest/status endpoint returns JSON with the EHRbase, openEHR, Java and PostgreSQL versions, which confirms the openEHR REST API is up:

active active {"ehrbase_version":"2.34.0","openehr_sdk_version":"2.34.0","archie_version":"3.13.0","jvm_version":"Eclipse Adoptium 25.0.3+9-LTS","os_version":"Linux amd64 6.17.0-1020-azure","postgres_version":"PostgreSQL 16.14 (Ubuntu 16.14-0ubuntu0.24.04.1) ..."}

On the very first boot, allow a minute or two for the database migration and the API server to start before the endpoint responds.

Step 5 - Retrieve your credentials

On first boot, EHRbase's built-in ehrbase-admin and ehrbase-user Basic-auth passwords are rotated to values unique to your VM. They are written to a root-only file. Read it with sudo. The output has these keys:

sudo cat /root/ehrbase-credentials.txt
EHRBASE_ADMIN_USERNAME=ehrbase-admin EHRBASE_ADMIN_PASSWORD=<generated-per-VM> EHRBASE_USER_USERNAME=ehrbase-user EHRBASE_USER_PASSWORD=<generated-per-VM> EHRBASE_URL=http://<vm-address>:8080/ehrbase/

Use the ehrbase-user account for openEHR data access: creating EHRs, and storing and querying compositions. Use the ehrbase-admin account for privileged operations. Both authenticate with HTTP Basic auth.

Step 6 - Confirm the secure defaults

EHRbase holds sensitive health data, so the image ships with no usable default credential. Confirm the rotation from the shell. The publicly documented default password SuperSecretPassword is rejected, while the per-VM password from the credentials file authenticates.

PASS=$(sudo grep '^EHRBASE_USER_PASSWORD=' /root/ehrbase-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'default password: HTTP %{http_code}\n' -X POST -u 'ehrbase-user:SuperSecretPassword' \
  -H 'Content-Type: application/json' http://127.0.0.1:8080/ehrbase/rest/openehr/v1/ehr
curl -s -o /dev/null -w 'per-VM password: HTTP %{http_code}\n' -X POST -u "ehrbase-user:$PASS" \
  -H 'Content-Type: application/json' http://127.0.0.1:8080/ehrbase/rest/openehr/v1/ehr
default password: HTTP 401 per-VM password: HTTP 201

The 401 for the built-in default and 201 for the per-VM password prove the first-boot rotation.

The two PostgreSQL role passwords are rotated in the same way on first boot. EHRbase's insecure default profile, which would disable authentication, is switched off.

Step 7 - Call the openEHR REST API

EHRbase is driven entirely through the standard openEHR REST API. Authenticate with HTTP Basic auth using the ehrbase-user credential. Then create an EHR, the fundamental container for a subject's health record:

PASS=$(sudo grep '^EHRBASE_USER_PASSWORD=' /root/ehrbase-credentials.txt | cut -d= -f2-)
curl -s -D - -o /dev/null -X POST -u "ehrbase-user:$PASS" \
  -H 'Content-Type: application/json' -H 'Prefer: return=representation' \
  http://127.0.0.1:8080/ehrbase/rest/openehr/v1/ehr | grep -iE 'HTTP/|ETag|Location'

EHRbase creates a new EHR and returns 201 Created with the new ehr_id in the Location and ETag headers:

HTTP/1.1 201 Location: http://127.0.0.1:8080/ehrbase/rest/openehr/v1/ehr/869e9ad6-0d7b-44c2-915d-f68393ea5166 ETag: "869e9ad6-0d7b-44c2-915d-f68393ea5166"

Use that ehr_id to store and retrieve compositions for the subject.

The full openEHR REST API is served under http://<vm-address>:8080/ehrbase/rest/openehr/v1/. It covers EHRs, compositions, contributions, templates, directories and the AQL query endpoint.

Step 8 - Upload an operational template

openEHR stores clinical data as compositions that conform to an operational template. This is an .opt file exported from a modeling tool such as the openEHR Archetype Designer.

Upload a template once, then post compositions against it. Templates are managed under the openEHR definition/template/adl1.4 endpoint:

PASS=$(sudo grep '^EHRBASE_USER_PASSWORD=' /root/ehrbase-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'upload: HTTP %{http_code}\n' -X POST -u "ehrbase-user:$PASS" \
  -H 'Content-Type: application/xml' --data-binary @your-template.opt \
  http://127.0.0.1:8080/ehrbase/rest/openehr/v1/definition/template/adl1.4

A 201 response means the template is registered. You can then POST compositions that reference its template ID to .../ehr/<ehr_id>/composition. To list the templates already loaded, send a GET to the same endpoint.

Step 9 - Query with AQL

The Archetype Query Language endpoint queries across EHRs and compositions in a template-agnostic way. Count the EHRs in the repository:

PASS=$(sudo grep '^EHRBASE_USER_PASSWORD=' /root/ehrbase-credentials.txt | cut -d= -f2-)
curl -s -u "ehrbase-user:$PASS" -H 'Accept: application/json' \
  --data-urlencode 'q=SELECT COUNT(e/ehr_id/value) FROM EHR e' -G \
  http://127.0.0.1:8080/ehrbase/rest/openehr/v1/query/aql

The response is an openEHR result set in JSON, with the count in the rows array:

{"meta":{"_type":"RESULTSET", ...},"q":"SELECT COUNT(e/ehr_id/value) FROM EHR e", "columns":[{"name":"#0"}],"rows":[[0]]}

On a fresh appliance the count is 0, and each EHR you create increments it.

AQL is the primary way applications and analytics pipelines read structured data back out of EHRbase. You query fields by their openEHR path (here e/ehr_id/value) rather than the full object.

Putting EHRbase behind TLS

The image serves the openEHR API over plain HTTP on port 8080. This suits a private network or a co-located application.

For anything exposed more widely, terminate TLS in front of EHRbase with your own reverse proxy (nginx, Caddy or Azure Application Gateway) and forward to http://127.0.0.1:8080/ehrbase/.

If you need OAuth2/OIDC instead of Basic auth, put EHRbase behind your identity provider. EHRbase supports an OAUTH security mode that you can switch to in /etc/ehrbase/ehrbase.env.

Backup and maintenance

EHRbase keeps all of its clinical data in its PostgreSQL backing database. This includes EHRs, compositions, templates and the AQL indexes. Back it up regularly:

sudo -u postgres pg_dump ehrbase > /tmp/ehrbase-db-$(date +%F).sql

Ship the dump to Azure Blob Storage or another object store. Alternatively, snapshot the OS disk in Azure for a coordinated point-in-time backup.

Keep the OS patched with sudo apt update && sudo apt upgrade. To upgrade EHRbase itself, follow the vendor upgrade notes for your target version and take a database backup first. EHRbase migrates its schema automatically on the next start.

Support

SecureAnyCloud supports this image 24/7. Contact us by email and chat for help with deployment, openEHR template and archetype modeling, AQL query design, reverse-proxy and TLS termination, identity-provider integration and PostgreSQL administration. Email sales@secureanycloud.com.

For general EHRbase questions, see the documentation at https://ehrbase.readthedocs.io and https://github.com/ehrbase/ehrbase.

EHRbase is an open-source project, and openEHR is a trademark of the openEHR Foundation. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.

Deploy on Azure

Launch EHRbase on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure