Installation
Note
If you don’t already have a license, you can request a license key at https://open-fhir.com#access. License will be provided automatically to you via email.
Docker
openFHIR can be easily installed using Docker. The official Docker image is available at openfhir/openfhir-enterprise:latest (build tag is also available).
To run Open-FHIR using Docker, use the following command:
docker run -e SPRING_DATA_MONGODB_URI=mongodb://your-mongodb-url \
-e OPENFHIR_DB_TYPE=mongo \
-e OPENFHIR_LICENSE=/path/to/license \
-p 8080:8080 openfhir/openfhir-enterprise:latest
Database
At the moment, MongoDB and PostgreSQL are supported. There is no default: set openfhir.db.type
(OPENFHIR_DB_TYPE) to mongo or postgres, otherwise the engine does not start (see Startup checks).
MongoDB
-e OPENFHIR_DB_TYPE=mongo
or in docker compose
services:
openfhir:
....
environment:
SPRING_DATA_MONGODB_URI: "mongodb://openfhir:openfhir@mongodb:27017/openfhir"
OPENFHIR_DB_TYPE: "mongo"
Postgres
-e OPENFHIR_DB_TYPE=postgres
or in docker compose
services:
openfhir:
....
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/openfhir
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: postgres
OPENFHIR_DB_TYPE: "postgres"
Connections to PostgreSQL are pooled (HikariCP, pool openfhir-postgres). The pool is tuned with the standard Spring Boot
spring.datasource.hikari.* properties, e.g. SPRING_DATASOURCE_HIKARI_MAXIMUM_POOL_SIZE (default 10) or
SPRING_DATASOURCE_HIKARI_CONNECTION_TIMEOUT (milliseconds, default 30000). Every node keeps its own pool, so in a
multi-node deployment (see High Availability) the number of nodes times the maximum pool size must stay below the server’s
max_connections (100 by default in PostgreSQL), leaving room for other clients.
Database stores the following state:
bootstrapEntity: ledger of all files that were bootstrapped, recording each file’s path, a hash of the content that was applied and the entity it created, so that a re-run can tell an unchanged file (skipped) from a changed one (updated in place) and a new one (created). See more: State configuration
conceptMapFhirEntity: concept maps for terminology (see more: Terminology)
fhirConnectContextEntity: FHIR Connect context mappers
fhirConnectMapperEntity: FHIR Connect model mappers
optEntity: Operational templates (unless the engine is integrated to an external openEHR repository, see more: Integrations)
Example docker compose - postgres
services:
openfhir:
image: openfhir/openfhir-enterprise:latest
restart: always
network_mode: host
container_name: openfhir
ports:
- "8080:8080"
volumes:
- "/opt/openfhir/config/examples/:/home/"
- "/opt/openfhir/config/license.json:/app/openfhir-license.json"
- "/opt/openfhir/config/bootstrap/:/app/bootstrap/"
- "/opt/openfhir/config/application.yaml:/application.yaml"
postgres:
image: postgres:16
network_mode: host
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- "/opt/openfhir/config/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql"
init-db.sql
-- Create OpenFHIR database and user
CREATE DATABASE openfhir;
CREATE USER openfhir WITH ENCRYPTED PASSWORD 'openfhir';
GRANT ALL PRIVILEGES ON DATABASE openfhir TO openfhir;
-- Ensure the users can connect and create objects within their databases
ALTER DATABASE openfhir OWNER TO openfhir;
-- Grant privileges to schemas (optional but recommended)
ALTER ROLE openfhir SET search_path TO public;
application.yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/openfhir
username: openfhir
password: openfhir
server:
error:
include-stacktrace: never
include-message: always
port: 8080
openfhir:
db:
type: postgres
license: /app/openfhir-license.json
bootstrap:
dir: /app/bootstrap
recursively-open-directories: true
Example docker compose - mongo
Example docker compose file
services:
openfhir:
image: openfhir/openfhir-enterprise:latest
container_name: openfhir
ports:
- "8080:8080"
volumes:
- "/home/user/Documents/openFHIR/license.json:/app/openfhir-license.json"
- "/home/user/Documents/openFHIR/openfhir-bootstrap/:/app/bootstrap/"
environment:
SPRING_DATA_MONGODB_URI: "mongodb://openfhir:openfhir@mongodb:27017/openfhir"
OPENFHIR_DB_TYPE: "mongo"
OPENFHIR_LICENSE: "/app/openfhir-license.json" # could also be left out, as this is the default
OPENFHIR_BOOTSTRAP_DIR: "/app/bootstrap/" # could also be left out, as this is the default
mongodb:
image: mongo:latest
container_name: mongodb
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: "admin"
MONGO_INITDB_ROOT_PASSWORD: "admin"
MONGO_INITDB_DATABASE: "openfhir"
volumes:
- ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
init-mongo.js
// Connect to the admin database to create a user for a specific database
db = db.getSiblingDB('openfhir');
// Create a new user with readWrite access to the 'openfhir' database
db.createUser({
user: 'openfhir',
pwd: 'openfhir',
roles: [
{
role: 'readWrite',
db: 'openfhir'
}
]
});
Startup checks
The engine checks its license and database configuration at startup. When something is wrong it stops and logs
an APPLICATION FAILED TO START block that says what is wrong and what to do about it, for example:
***************************
APPLICATION FAILED TO START
***************************
Description:
openFHIR license file not found at '/app/openfhir-license.json'.
Action:
Place your license file at that path or point 'openfhir.license' to where it is (relative paths are resolved against the working directory). To obtain a license, visit https://open-fhir.com or contact us at info@open-fhir.com.
This is reported for:
a license that is not configured, cannot be found or read, is not a license file, has been modified or has expired (
OPENFHIR_LICENSE)an
OPENFHIR_DB_TYPEother thanmongoorpostgresmissing database connection settings:
SPRING_DATA_MONGODB_URIformongo;SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAMEandSPRING_DATASOURCE_PASSWORD(which may be empty) forpostgresa database that cannot be reached, whose host does not resolve, that rejects the credentials or the connection, (MongoDB) whose TLS handshake fails or (PostgreSQL) whose database does not exist. Hosts are named, credentials never are
invalid queue configuration, or queue support enabled without the
messaginglicense option (see Queue support)
The full stack trace of the failure is logged at DEBUG level
(LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_BOOT_DIAGNOSTICS=DEBUG).
License expiry
The license file is validated again once a day. Its expiry date and options are logged at startup and with every
check; from 30 days before expiry this is a WARN. GET /status reports them under license (see
RESTful APIs).
To renew, overwrite the file at OPENFHIR_LICENSE with the new license before the old one expires (e.g.
cp new-license.json license.json); the daily check picks it up without a restart, including options the new
license adds or removes (e.g. terminology). The messaging option is only checked at startup, so queue support
is switched on or off by a new license only after a restart.
Note
When the license is mounted as a single file, as in the Docker examples above, the container does not see a file
that is replaced rather than overwritten (mv, or an editor that saves by renaming), so overwrite it in place.
Alternatively, mount a directory of its own and point OPENFHIR_LICENSE into it, e.g.
-v /opt/openfhir/license:/app/license:ro with OPENFHIR_LICENSE=/app/license/openfhir-license.json. Do not
mount over /app itself, which holds the engine. A Kubernetes Secret or ConfigMap only reaches a running
container when it is mounted as a directory, not with subPath; otherwise restart the engine after renewing.
When the check finds the license no longer valid, it logs what is wrong and what to do about it, and checks again 30
seconds later, so a file that is being overwritten or is briefly unavailable does not stop the engine. If the license
is still not valid, the engine shuts down gracefully (in-flight requests, queue consumers and cluster membership are
closed cleanly) and exits with code 1. If that does not finish within 60 seconds, the process is halted. With a
restart policy, the engine then fails to start again with an APPLICATION FAILED TO START message until a valid
license is in place.