Setting up your own FHIR server

Note that the urls in this post are a bit outdated – here is more up to date info about the HAPI CLI

I’ve been having some conversations with a group that are wanting to use clinFHIR to view profiles – and create sample resources from them – but they are using Forge to create them (good choice!) and so the question becomes about how to put them where clinFHIR can access them.

Before we get into the detail, lets take a step back and look at what we need to achieve to support clinFHIR in this way.

ClinFHIR has the concept of ‘server roles’. We’ve talked about them before, but in summary there are 3 of them:

  • The Patient/Data server that holds the Patient resources, and all of the ‘non-conformance’ resources – those that represent clinical data and supporting ones such as Practitioner or Organization
  • The Conformance (or Registry) server that holds the ‘definitional’ resources like StructureDefinition (Profile and Extension definition), NamingSystem and a few others
  • The Terminology server that has both ValueSet resources, and also exposes a number of terminology services (like $expand) that clinFHIR uses to populate drop downs from a ValueSet.

(Note that this is just how clinFHIR works – it’s not a FHIR requirement – but it does support the idea of a single place to place the ‘infrastructural’ resources that multiple data servers in an environment can then use).

And also note that these are ‘roles’ – they could all be performed by the same physical server if needed.

Here’s clinFHIR configured to use HAPI STU-3 as the Patient/Data server, and Grahames STU-3 server as the Conformance (‘My Profile’) and Terminology servers. (Note that all servers should be on the same FHIR version).


This distribution of roles has an impact when creating Profiles. Generally you’re going to be creating at least 2 types of resource, that will be hosted on 2 of these server roles – StructureDefinition resources (Profile and Extension Definition), which will go on the Conformance server, and ValueSets that will go on the Terminology server.

So: if we’re setting up our own infrastructure to perform profiling we’re going to need a server (or servers) that can fulfill at least the Conformance and Terminology roles. As always we have a number of options, but the one we’re going to use is the HAPI ‘Command Line Interface’ (CLI) application produced by the clever Canadians who built the HAPI library – they’ve taken the library and wrapped it up into a complete server that anyone can download and use for free – how cool is that!

Just to emphasize that the server we’re going deploy is for testing purposes only – it has no security! You should definitely not upload any Personal Health Information to this server, and if you have a need for reliability you should consider hardening it – which is outside the scope of this post.

So here are the steps to set up your own FHIR server using HAPI. I’m going to assume that you are comfortable with the command line – or know someone who can help you out if you get stuck.

First, create a hosted server in the cloud. I use DigitalOcean as you can do the whole thing within a  few minutes and they have options starting from $5/month (though you really want a reasonable amount of RAM so the $20 / month version is probably advisable **Update – you do need the $20 version to get 2Gig of RAM**). This will give you an Ubuntu server in the cloud with an IP address and a password (though you can set up certificated access which is both more convenient and more secure). Note that the server must have Java 8 installed.

Next login to the server from the command line of your computer using SSH eg:


Note that we’re logging in as the root user in this case. There are more secure ways of doing this, but it keeps it simple for now.

Now we need to download the HAPI CLI application to the server. A good place to put this is in the /opt directory, so execute the following commands to move to that folder and download the file (we’ll use WGET to do so)

cd /opt

This will download version 2 of the CLI into the folder – you can get the latest version from the hapi download page.

Next unzip the downloaded file:


You are now ready to start the server. There are a number of ways of doing this – I’ve used the following command which seems to work most of the time, but Java can be a dark art at times (at least for me…)

java -jar hapi-fhir-cli.jar run-server

All going well, you will see a number of informational lines scroll by, ending in a declaration that you now have a fully functional dstu-2 server listening at the endpoint [ip]/baseDstu2:8080

But what if you want STU-3? Or a different port? Well, the server actually has a number of command line switches (they are documented in the hapi page) to change the port, set the FHIR version & so forth. This command line will start the server in STU-3 mode, and make it run in the background so that it doesn’t stop when you close the connection:

nohup java -jar hapi-fhir-cli.jar run-server -f dstu3 --allow-external-refs &

(I usually create a small shell script to save typing)

update: note that “–allow-external-refs” is added to the end of the command (you have to scroll horizontally to see it) as otherwise the CLI won’t accept resources that reference external entities. (Thanks to Philip Scott for discovering this – and other omissions in this post!)

Do note that although you can use either STU-2 or STU-3, you shouldn’t use the same instance for both on the same server as weird things will happen. (I found this out the hard way).

The server is currently empty, but it would be convenient to load the standard resources if it is going to act as a Conformance/Terminology server. This can easily be done as follows.

With the server running, open a new SSH connection to the server (by opening a new terminal window and re-issuing the SSH command), change to the folder where HAPI is installed and enter the following command:

hapi-fhir-cli upload-definitions -t http://localhost:8080/baseDstu3 


java -jar hapi-fhir-cli.jar upload-definitions -t http://localhost:8080/baseDstu3

(but replace ‘http://localhost:8080/baseDstu3’ with the base url of your own server)

Note that there is now a ‘version’ parameter needed – something like -v dtsu3 for example, or -v r4.

This will download all the conformance resources (StructureDefinition, ValueSet) from the main FHIR site to your local server.

So now you can point clinFHIR at your new server, select any of the standard resource types and view their profile. You can also create sample instances. To do this, you’ll need to tell clinFHIR about your new server – you can do so using the ‘Add Server’ option off the main menu:


And here is where you enter the server details:


…making sure you enter the correct Url of your server. (After entering the server url, click the ‘test’ button that appears to the lower right – that will check that the server is a valid FHIR server, and will display a ‘Add’ button if it is – ie it returns a Conformance/CapabilityStatement resource. You also need to select the FHIR version – though as I write this I realize that the app should be able to determine this from the CapabilityStatement – I’ll fix that later!)

(btw – this ‘add Server’ functionality only works on the Browser where you issued the command – and will be deleted if you need to reset the config. Something else for me to fix 🙂 )

There’s one last thing you might want to do, which is to install the SNOMED files on your server. This will allow the server to expand SNOMED based ValueSets when acting as a Terminology sever. The process is described here – but do be aware that there are licensing issues relating to the use of SNOMED, so make sure there are no issues before you do this.

Now that your server is all set up, you’re good to go with loading your own profiles on to it. There are (as always) a number of options for doing this.

The easiest is to simply use a REST client of some sort to copy them. You can either use a REST client with a User Interface (such as POSTman) and copy/paste the resource file into the tool then upload it – or use CURL which is a command line client that has been around for ever. Here’s an example of its use:

curl --upload-file ohCondition.structuredefinition.xml

It will upload the file ‘ohCondition.structuredefinition.xml’ in the current folder to the FHIR server at

(What I did was to create a shell script in the folder where the files are stored with a command for all the files I want to upload, then it’s easy to upload them just by executing the script. Remember to make the script executable!).

If you are using gitHub, then just create a local copy of the files by cloning the repo and execute the upload script after using ‘git pull’ to make sure you have the most recent copies of the files). Here’s a diagram of how it could work…


One ‘gotcha’ to be aware of, is that when you upload a resource to the HAPi server, it will check that any resources it references are already on the server, rejecting the resource if it does not. (I’m not 100% sure that I agree with this, but it is the behavior). The practical impact of this is that there is a distinct order of upload to follow (this can all be in the same script of course).

  1. All ValueSets referenced by any of the resources (if your server will be a Terminology Server)
  2. The StructureDefinitions that represent extension definitions
  3. The StructureDefinitions that represent profiled resources

(Another possible ‘gotcha’ is to make sure that Forge generates snapshots in the profiles…)

So there you go. A FHIR server of your very own for profiling!

Addendum: If you have issues with this installation, there is an active support group that you can use.

About David Hay
I'm an independent contractor working with a number of Organizations in the health IT space. I'm an HL7 Fellow, Chair Emeritus of HL7 New Zealand and a co-chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the FHIR standard. I'm the author of a FHIR training and design tool - clinFHIR - which is sponsored by InterSystems Ltd.

12 Responses to Setting up your own FHIR server

  1. Pingback: Building your own FHIR server | Hay on FHIR

  2. Pingback: Creating an Extension Definition – part 2: The URL. | Hay on FHIR

  3. Pingback: Building an Information model. | Hay on FHIR

  4. Hrushi says:

    is it same steps to create our own HAPI FHIR server setup at my end?
    Can you please help us.


    • David Hay says:

      Hi – Not sure what you mean – the post is all about setting up your own server….

  5. allen says:

    how to config myself localhost database?

    • David Hay says:

      Hi – This should happen automatically when the app first starts using a built-in database. But there are plenty of ways you can roll your own – check out the hapi page:


  6. Pingback: Provider Directories – part 1 | Hay on FHIR

  7. Hayhay says:

    Hello! I have a separate terminal open, I was able to follow the instructions to get my FHIR server running on r4. When I try to use the “hapi-fhir-cli upload-definitions -t http://localhost:8080/baser4 –fhir-version r4 ” command in my client terminal, I get the following, “2020-03-29 05:23:02.663 [main] INFO c.u.f.c.ValidationDataUploader Uploading definitions to server
    2020-03-29 05:23:05.592 [main] INFO c.u.f.c.ValidationDataUploader Uploading ValueSet 1/1167 : CodeSystem/example (2164 bytes}
    2020-03-29 05:23:05.750 [main] ERROR ca.uhn.fhir.cli.App Error during execution: HTTP 404 Not Found
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(
    at java.base/java.lang.reflect.Constructor.newInstance(”

    Any ideas on why I’m unable to download the definitions? I’ve tried fiddling with the command and the base URL but no luck :/

  8. Ratanak Phong says:

    The post is about “Setting up your own FHIR server“.
    I do not understand what you emphasize here “Just to emphasize that the server we’re going deploy is for testing purposes only – it has no security! You should definitely not upload any Personal Health Information to this server, and if you have a need for reliability you should consider hardening it – which is outside the scope of this post.”

    • David Hay says:

      Mostly to point out that you would some sort of security layer – possibly including both authentication and authorization (who the user is and what they can do) if there were real data in there…

  9. Pingback: Creating your own FHIR Server: revised | Hay on FHIR

Leave a Reply

%d bloggers like this: