---
# System prepended metadata

title: NGINX與HAPI FHIR整合
tags: [HAPI, FHIR, NGINX]

---

NGINX與HAPI FHIR整合
===

由於HAPI FHIR定位為開源軟體，因此就商業考量角度來看，community版本缺乏某些實際上線需要的功能，例如負載平衡、效能、監控、Log管理等。

改善方向可思考以下幾個方式：
1. 使用商業版：Smile Digial Health `https://www.smiledigitalhealth.com/`提供商業版本之HAPI FHIR。
2. 自行修改HAPI FHIR原始碼。
3. 整合其他開源軟體功能，如本文所敘述之NGINX。

NGINX使用案例如下圖所示：
![nginx-4](https://hackmd.io/_uploads/SkQu1_Ij6.png)

NGINX運作(https://nginx.org/en/docs/beginners_guide.html)：
* nginx has one master process and several worker processes. 
* The main purpose of the master process is to read and evaluate configuration, and maintain worker processes. 
* Worker processes do actual processing of requests. 
* nginx employs event-based model and OS-dependent mechanisms to efficiently distribute requests among worker processes. 
* The number of worker processes is defined in the configuration file and may be fixed for a given configuration or automatically adjusted to the number of available CPU cores.

NGING設定(https://nginx.org/en/docs/beginners_guide.html)：
* By default, the configuration file is named `nginx.conf` and placed in the directory `/usr/local/nginx/conf`, `/etc/nginx`, or `/usr/local/etc/nginx`.
* nginx consists of modules which are controlled by directives specified in the configuration file. 
* Directives are divided into simple directives and block directives.
  * A simple directive consists of the name and parameters separated by spaces and ends with a semicolon (;). 
  * A block directive has the same structure as a simple directive, but instead of the semicolon it ends with a set of additional instructions surrounded by braces ({ and }). 
* If a block directive can have other directives inside braces, it is called a context (examples: events, http, server, and location).
* Directives placed in the configuration file outside of any contexts are considered to be in the main context. 
* The `events` and `http` directives reside in the `main` context, `server` in `http`, and `location` in `server`.
```mermaid
graph TD;
main-->events;
main-->http;
http-->server;
server-->location;
```
* The rest of a line after the # sign is considered a comment.

Load Balancer設定
---
![nginx-5](https://hackmd.io/_uploads/B1YTC4ioT.png)

預計之系統架構如上圖所示，所有模組都是容器化，NGINX扮演Load Balancer角色，將外部的Request依照設定分配給後端HAPI FHIR。這不是最終的架構，下一階段將結合K8S，根據的效能需求，做即時的動態資源分配。

docker-compose檔
```
version: '3.7'

services:

  ngnix:
    container_name: nginx
    image: nginx:latest
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "80:80"
    depends_on:
      - fhir1
      - fhir2

  db:
    container_name: bmaindb
    image: postgres
    restart: always
    environment:
      POSTGRES_PASSWORD: hapipoc
      POSTGRES_USER: hapipoc
      POSTGRES_DB: hapi
    # not needed for networking between containers but here for troubleshooting
    ports:
      - "5433:5432"

  fhir1:
    container_name: bmainfhir1
    image: hapiproject/hapi:latest
    ports:
      - "8081:8080"
    environment:
      HAPI_FHIR_USERNAME : admin
      HAPI_FHIR_PASSWORD : admin
      profiles.active: r4
    configs:
      - source: hapi
        target: /app/config/application.yaml
    depends_on:
      - db

  fhir2:
    container_name: bmainfhir2
    image: hapiproject/hapi:latest
    ports:
      - "8082:8080"
    environment:
      HAPI_FHIR_USERNAME : admin
      HAPI_FHIR_PASSWORD : admin
      profiles.active: r4
    configs:
      - source: hapi
        target: /app/config/application.yaml
    depends_on:
      - db

configs:
  hapi:
     file: ./hapi.application.yaml
```
nginx.conf檔
```
events { worker_connections 1024; }

http {

    upstream api_servers {    # Create an upstream for the web servers
        server fhir1:8080;    # the first server
        server fhir2:8080;    # the second server
    }

    server {
        listen 80;

        location / {
            proxy_pass http://api_servers;  # load balance the traffic
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}
```


