Deployment guide

Open Integration Engine

Overview

Open Integration Engine (OIE) is a community-governed, MPL-2.0-licensed integration engine for healthcare interoperability. You build channels that receive, filter, transform and route messages between systems. It has first-class support for HL7 v2, FHIR, DICOM, X12, XML, JSON and delimited formats, plus JavaScript transformers and connectors for HTTP, TCP/MLLP, files, databases and JMS.

This image ships version 4.6.0 on Microsoft Azure, with an admin password generated uniquely for your VM. This guide walks you through deploying it, signing in, and pushing your first message through a channel.

What the image gives you

  • Engine: Open Integration Engine 4.6.0 on OpenJDK 17
  • Base OS: Ubuntu 24.04 LTS, fully patched at build time
  • Web edge: nginx on port 443 (TLS) in front of the engine. Port 80 serves a health endpoint and redirects to HTTPS.
  • Admin credential: generated per VM on first boot. No shared or default password ships in the image.
  • Data: embedded Derby database, keystore and configuration on a dedicated 20 GiB Azure data disk
  • Self test: oie-engine-selftest.sh proves that the engine really processes a message
  • Recommended size: Standard_B2s (2 vCPU / 4 GiB) for evaluation and light workloads

Compliance note. This image is infrastructure. You remain responsible for every HIPAA, PHI and GDPR control that applies to your deployment, including your own domain with a trusted TLS certificate, network isolation, access control, audit logging and encryption at rest. Nothing here is certified compliant.

1. Launch the VM

From the Azure portal

  • Open the offer in the Azure Marketplace and choose Get It Now, then Create.
  • Pick your subscription, resource group and region.
  • Choose a VM size. Standard_B2s is enough to evaluate the engine and run light channel traffic. Scale up for production throughput.
  • Set the administrative username to azureuser and supply your SSH public key.
  • On the Networking tab, allow inbound 22 (SSH) and 443 (HTTPS). Port 80 is optional and only serves a health endpoint plus a redirect to HTTPS.
  • Create the VM.

From the Azure CLI

Run these commands on your own workstation, not on the VM:

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:open-integration-engine-ubuntu-24-04:default:latest
az vm create \
  --resource-group my-resource-group \
  --name my-oie-vm \
  --image sac1647283583153:open-integration-engine-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard
# Then open only the ports you need, restricted to the networks that should reach them.
az vm open-port --resource-group my-resource-group --name my-oie-vm \
  --port 443 --priority 1010 --source-address-prefixes <your-mgmt-cidr>
az vm open-port --resource-group my-resource-group --name my-oie-vm \
  --port 22 --priority 1020 --source-address-prefixes <your-mgmt-cidr>

First boot takes about a minute. The engine creates a fresh database, rotates the admin password to a value unique to your VM, and generates a TLS certificate for this VM. Only then does it start nginx.

2. Retrieve your per-VM admin password

The image ships no usable credential. First boot generates the password on your VM and writes it to a root-only file. Connect over SSH and read the file:

ssh azureuser@<vm-ip>
sudo cat /root/oie-credentials.txt
# Open Integration Engine - generated on first boot by oie-firstboot.service
# These credentials are unique to this VM. Store them somewhere safe. OIE_URL=https://<vm-ip>/ OIE_API_BASE=https://<vm-ip>/api OIE_USERNAME=admin OIE_PASSWORD=<OIE_PASSWORD>

Copy the password into your password manager, then confirm the services are healthy:

systemctl status oie nginx --no-pager --lines=5

You can see exactly what first boot did. The journal shows the credential rotation and the proof that the old default login no longer works:

sudo journalctl -u oie-firstboot.service --no-pager | tail -14

3. Open the web interface

Browse to https://<vm-public-ip>/.

The appliance uses a self-signed certificate generated for your VM, so your browser warns you the first time. Accept the warning for evaluation. See section 8 before you go to production.

This landing page confirms that the backend is running. It also gives you the URL to point an Administrator Launcher at. Two things are worth understanding here:

  • Channel authoring happens in the Administrator, a desktop application that you download separately from the project. Point it at the URL shown on this page and sign in as admin with your per-VM password.
  • Everything the Administrator does is also available over the REST API, which is fully browsable on this VM. This guide uses the API, because it works from any machine with curl and needs nothing installed.

4. Explore the Client API

Click Go to API, or browse to https://<vm-public-ip>/api/.

Expanding Channels shows the operations you use to create, deploy, start, stop and inspect channels.

One API rule to remember. The engine ships with server.api.require-requested-with = true, so every REST call must carry an X-Requested-With header. The API explorer adds it for you. From curl, add it yourself, as shown below.

Without the header, the engine replies 400 All requests must have 'X-Requested-With' header.

Sign in from the command line and keep the session cookie:

PW=$(sudo grep '^OIE_PASSWORD=' /root/oie-credentials.txt | cut -d= -f2-)
curl -sk -c /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  --data-urlencode 'username=admin' \
  --data-urlencode "password=${PW}" \
  https://127.0.0.1/api/users/_login

A successful sign-in returns a LoginStatus of SUCCESS. Check the engine version the same way:

curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  https://127.0.0.1/api/server/version
4.6.0

5. Prove the engine works, in one command

A web page returning 200 tells you that a web server is up. It does not tell you that the engine can actually move a message. The image ships a self test that answers the real question. It deploys a temporary channel, pushes an HL7 v2 message through it, checks the engine's own statistics, and removes the channel again.

sudo /usr/local/sbin/oie-engine-selftest.sh

received=1 sent=1 error=0 means the message travelled through the source connector, the transformer and the destination connector.

Run the self test any time you want to confirm that the engine is healthy, including after you change configuration.

6. Deploy your first channel

The image ships the self test's channel definition at /usr/share/sac/oie/example-channel.xml so you can run this section verbatim. It is a minimal Channel Reader source feeding a JavaScript Writer destination.

Give the channel an id and a name of your own:

CHANNEL_ID=$(cat /proc/sys/kernel/random/uuid)
echo "${CHANNEL_ID}" | sudo tee /tmp/oie-channel-id >/dev/null
sudo sed -e "s/SAC_CHANNEL_ID/${CHANNEL_ID}/" \
  -e "s/SAC_CHANNEL_NAME/my-first-channel/" \
  /usr/share/sac/oie/example-channel.xml | sudo tee /tmp/my-channel.xml >/dev/null echo "prepared channel ${CHANNEL_ID}"

Create the channel:

curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  -H 'Content-Type: application/xml' \
  --data-binary @/tmp/my-channel.xml \
  -o /dev/null -w 'create: HTTP %{http_code}\n' \
  https://127.0.0.1/api/channels

Deploy the channel:

CHANNEL_ID=$(cat /tmp/oie-channel-id)
curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  -H 'Content-Type: application/xml' \
  --data "<set><string>${CHANNEL_ID}</string></set>" \
  -o /dev/null -w 'deploy: HTTP %{http_code}\n' \
  "https://127.0.0.1/api/channels/_deploy?returnErrors=true"

Confirm it reached STARTED:

CHANNEL_ID=$(cat /tmp/oie-channel-id) for i in $(seq 1 30); do
STATE=$(curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  "https://127.0.0.1/api/channels/${CHANNEL_ID}/status" | grep -oE '<state>[A-Z]+</state>')
echo "${STATE}" case "${STATE}" in *STARTED*) break;; esac sleep 2 done

Push an HL7 v2 message through the channel:

CHANNEL_ID=$(cat /tmp/oie-channel-id)
curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  -H 'Content-Type: text/plain' \
  --data-binary 'MSH|^~\&|SENDING_APP|SENDING_FAC|RECEIVING_APP|RECEIVING_FAC|20260101000000||ADT^A01|MSG00001|P|2.5' \
  -w '\nsubmit: HTTP %{http_code}\n' \
  "https://127.0.0.1/api/channels/${CHANNEL_ID}/messages?destinationMetaDataId=1"

Do not omit destinationMetaDataId. It names the destination connectors that the message should be routed to.

Without the parameter, the engine accepts the message and runs the source connector only. Statistics show received=1 and sent=0 forever, and your destinations never fire. This is the single most common surprise when driving the engine from the REST API.

Check the statistics. received and sent should both be 1:

CHANNEL_ID=$(cat /tmp/oie-channel-id)
curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  "https://127.0.0.1/api/channels/${CHANNEL_ID}/statistics"

When you are finished with the example, undeploy and remove it:

CHANNEL_ID=$(cat /tmp/oie-channel-id)
curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  -H 'Content-Type: application/xml' \
  --data "<set><string>${CHANNEL_ID}</string></set>" \
  -o /dev/null -w 'undeploy: HTTP %{http_code}\n' \
  https://127.0.0.1/api/channels/_undeploy
curl -sk -b /tmp/oie-cookies -H 'X-Requested-With: XMLHttpRequest' \
  -X DELETE -o /dev/null -w 'delete: HTTP %{http_code}\n' \
  "https://127.0.0.1/api/channels/${CHANNEL_ID}"

To build real channels, export a definition from the Administrator and create the channel the same way.

7. Opening ports for your own channel listeners

The image opens only what the appliance itself needs: 22, 80 and 443.

Listener ports belong to the channels you create. An MLLP listener on 6661, an HTTP listener on 8081 or a TCP listener on any port binds on the VM as soon as you deploy the channel. Azure does not admit traffic to it until you open that port too:

az vm open-port --resource-group my-resource-group --name my-oie-vm \
  --port 6661 --priority 1030 --source-address-prefixes <your-mgmt-cidr>

Open only the ports you actually use. Restrict the source address range on the NSG rule to the systems that are meant to talk to the engine.

8. Security posture and hardening

The image is secure by default in three specific ways.

No known credential ships in the image. The engine's database is wiped before the image is captured, so the captured image contains no account at all. Your VM creates the database fresh on first boot. It rotates the admin password to a value unique to your VM before it starts the public web edge.

The engine is not directly exposed. Its admin and REST listeners bind to 127.0.0.1 only. nginx on ports 80 and 443 is the sole public edge. Check the listeners with:

sudo ss -tlnp | grep -E ':8443|:8080|:443|:80 '

The old default login is provably dead. Check this yourself at any time:

curl -sk -H 'X-Requested-With: XMLHttpRequest' \
  --data-urlencode 'username=admin' --data-urlencode 'password=admin' \
  https://127.0.0.1/api/users/_login

This returns <status>FAIL</status>. If it ever returns SUCCESS, stop and rebuild the VM.

Before production

  • Replace the TLS certificate. Point a DNS name at the VM and install a trusted certificate:

bash sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx sudo certbot --nginx -d oie.example.com

  • Restrict access. Limit inbound 443 to the networks that need the Administrator or API, using an NSG rule or a private endpoint.
  • Change the admin password to one of your own, and create named per-person accounts rather than sharing admin.
  • Back up the data disk. Everything stateful lives on it, so an Azure snapshot schedule against that disk captures your channels and message history.

9. Where everything lives

Path Contents

/opt/oie Engine installation, launcher, extensions and logs

/opt/oie/conf/mirth.properties Engine configuration, including the loopback bind and data directory

/opt/oie/conf/custom.vmoptions JVM options, including the heap size

/var/lib/oie/appdata Data disk. Derby database, keystore, configuration map and temporary data

/root/oie-credentials.txt Your per-VM admin credentials, root readable only

/usr/local/sbin/oie-engine-selftest.sh The engine self test

Service management:

sudo systemctl status oie
sudo systemctl restart oie
sudo journalctl -u oie -f

Tuning the JVM heap

The image sets a 1 GiB maximum heap, which suits Standard_B2s. If you move to a larger VM and drive real message volume, raise the heap:

sudo sed -i 's/^-Xmx1024m/-Xmx3072m/' /opt/oie/conf/custom.vmoptions
sudo systemctl restart oie

Leave at least a gigabyte for the operating system, nginx and the database cache. Never add a swap file to compensate for an undersized VM. Move to a larger size instead.

10. Troubleshooting

The web page does not load. Confirm nginx is running and port 443 is open in the NSG:

sudo systemctl status nginx --no-pager curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthz

/healthz returns 200 from the VM itself whenever the edge is healthy.

The credentials file still shows <OIE_PASSWORD> instead of a password. First boot has not finished. Watch it:

sudo journalctl -u oie-firstboot.service -f

The engine's first start creates the database and can take up to a couple of minutes.

A REST call returns 400. You omitted the X-Requested-With header. See section 4.

A channel receives messages but never sends them. You omitted destinationMetaDataId when submitting the message. See section 6.

The engine will not start after a configuration change. Check the log:

sudo journalctl -u oie --no-pager | tail -50 sudo tail -50 /opt/oie/logs/mirth.log

Support

This image is maintained by SecureAnyCloud with 24/7 support for deployment, upgrades, TLS setup and channel configuration questions. Contact sales@secureanycloud.com.

Open Integration Engine itself is open source under the Mozilla Public License 2.0. Project documentation, the Administrator Launcher downloads and the community are at openintegrationengine.org.

Deploy on Azure

Launch Open Integration Engine 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