Merge pull request #424 from dannyrb/docs/last-bits
Note regarding different repositories
This commit is contained in:
commit
12eefb3108
16
docker/OpenResty-Orthanc/.dockerignore
Normal file
16
docker/OpenResty-Orthanc/.dockerignore
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Output
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Root
|
||||||
|
README.md
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
# Misc. Config
|
||||||
|
.git
|
||||||
|
.DS_Store
|
||||||
|
.gitignore
|
||||||
|
.vscode
|
||||||
|
.circleci
|
||||||
5
docker/OpenResty-Orthanc/.env
Normal file
5
docker/OpenResty-Orthanc/.env
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Docker ENV and ARG Variables
|
||||||
|
# ----------------------------
|
||||||
|
# https://vsupalov.com/docker-arg-env-variable-guide/
|
||||||
|
#
|
||||||
|
#
|
||||||
135
docker/OpenResty-Orthanc/config/nginx.conf
Normal file
135
docker/OpenResty-Orthanc/config/nginx.conf
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
worker_processes 2;
|
||||||
|
error_log /var/logs/nginx/mydomain.error.log;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
include /usr/share/nginx/modules/*.conf; # See /usr/share/doc/nginx/README.dynamic.
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024; ## Default: 1024
|
||||||
|
use epoll; # http://nginx.org/en/docs/events.html
|
||||||
|
multi_accept on; # http://nginx.org/en/docs/ngx_core_module.html#multi_accept
|
||||||
|
}
|
||||||
|
|
||||||
|
# Core Modules Docs:
|
||||||
|
# http://nginx.org/en/docs/http/ngx_http_core_module.html
|
||||||
|
http {
|
||||||
|
include '/usr/local/openresty/nginx/conf/mime.types';
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
keepalive_requests 100000;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
|
||||||
|
# lua_ settings
|
||||||
|
#
|
||||||
|
lua_package_path '/usr/local/openresty/lualib/?.lua;;';
|
||||||
|
lua_shared_dict discovery 1m; # cache for discovery metadata documents
|
||||||
|
lua_shared_dict jwks 1m; # cache for JWKs
|
||||||
|
# lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||||
|
|
||||||
|
variables_hash_max_size 2048;
|
||||||
|
server_names_hash_bucket_size 128;
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
|
resolver 8.8.8.8 valid=30s ipv6=off;
|
||||||
|
resolver_timeout 11s;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
# Nginx `listener` block
|
||||||
|
server {
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
listen 80;
|
||||||
|
# listen 443 ssl;
|
||||||
|
access_log /var/logs/nginx/mydomain.access.log;
|
||||||
|
|
||||||
|
# Domain to protect
|
||||||
|
server_name 127.0.0.1 localhost; # mydomain.com;
|
||||||
|
proxy_intercept_errors off;
|
||||||
|
# ssl_certificate /etc/letsencrypt/live/mydomain.co.uk/fullchain.pem;
|
||||||
|
# ssl_certificate_key /etc/letsencrypt/live/mydomain.co.uk/privkey.pem;
|
||||||
|
gzip on;
|
||||||
|
gzip_types text/css application/javascript application/json image/svg+xml;
|
||||||
|
gzip_comp_level 9;
|
||||||
|
etag on;
|
||||||
|
|
||||||
|
# https://github.com/bungle/lua-resty-session/issues/15
|
||||||
|
set $session_check_ssi off;
|
||||||
|
lua_code_cache off;
|
||||||
|
set $session_secret Eeko7aeb6iu5Wohch9Loo1aitha0ahd1;
|
||||||
|
set $session_storage cookie;
|
||||||
|
|
||||||
|
server_tokens off; # Hides server version num
|
||||||
|
|
||||||
|
# Reverse Proxy for `orthanc` admin
|
||||||
|
#
|
||||||
|
location /pacs-admin/ {
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
expires 0;
|
||||||
|
add_header Cache-Control private;
|
||||||
|
|
||||||
|
proxy_pass http://orthanc:8042/;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reverse Proxy for `orthanc` APIs (including DICOMWeb)
|
||||||
|
#
|
||||||
|
location /pacs/ {
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
expires 0;
|
||||||
|
add_header Cache-Control private;
|
||||||
|
|
||||||
|
proxy_pass http://orthanc:8042/;
|
||||||
|
|
||||||
|
# By default, this endpoint is protected by CORS (cross-origin-resource-sharing)
|
||||||
|
# You can add headers to allow other domains to request this resource.
|
||||||
|
# See the "Updating CORS Settings" example below
|
||||||
|
}
|
||||||
|
|
||||||
|
# Do not cache sw.js, required for offline-first updates.
|
||||||
|
location /sw.js {
|
||||||
|
add_header Cache-Control "no-cache";
|
||||||
|
proxy_cache_bypass $http_pragma;
|
||||||
|
proxy_cache_revalidate on;
|
||||||
|
expires off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Single Page App
|
||||||
|
# Try files, fallback to index.html
|
||||||
|
#
|
||||||
|
location / {
|
||||||
|
alias /var/www/html/;
|
||||||
|
index index.html;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||||
|
}
|
||||||
|
|
||||||
|
# EXAMPLE: Redirect server error pages to the static page /40x.html
|
||||||
|
#
|
||||||
|
# error_page 404 /404.html;
|
||||||
|
# location = /40x.html {
|
||||||
|
# }
|
||||||
|
|
||||||
|
# EXAMPLE: Redirect server error pages to the static page /50x.html
|
||||||
|
#
|
||||||
|
# error_page 500 502 503 504 /50x.html;
|
||||||
|
# location = /50x.html {
|
||||||
|
# }
|
||||||
|
}
|
||||||
|
}
|
||||||
89
docker/OpenResty-Orthanc/config/orthanc.json
Normal file
89
docker/OpenResty-Orthanc/config/orthanc.json
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"Name": "Orthanc inside Docker",
|
||||||
|
"StorageDirectory": "/var/lib/orthanc/db",
|
||||||
|
"IndexDirectory": "/var/lib/orthanc/db",
|
||||||
|
"StorageCompression": false,
|
||||||
|
"MaximumStorageSize": 0,
|
||||||
|
"MaximumPatientCount": 0,
|
||||||
|
"LuaScripts": [],
|
||||||
|
"Plugins": ["/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"],
|
||||||
|
"ConcurrentJobs": 2,
|
||||||
|
"HttpServerEnabled": true,
|
||||||
|
"HttpPort": 8042,
|
||||||
|
"HttpDescribeErrors": true,
|
||||||
|
"HttpCompressionEnabled": true,
|
||||||
|
"DicomServerEnabled": true,
|
||||||
|
"DicomAet": "ORTHANC",
|
||||||
|
"DicomCheckCalledAet": false,
|
||||||
|
"DicomPort": 4242,
|
||||||
|
"DefaultEncoding": "Latin1",
|
||||||
|
"DeflatedTransferSyntaxAccepted": true,
|
||||||
|
"JpegTransferSyntaxAccepted": true,
|
||||||
|
"Jpeg2000TransferSyntaxAccepted": true,
|
||||||
|
"JpegLosslessTransferSyntaxAccepted": true,
|
||||||
|
"JpipTransferSyntaxAccepted": true,
|
||||||
|
"Mpeg2TransferSyntaxAccepted": true,
|
||||||
|
"RleTransferSyntaxAccepted": true,
|
||||||
|
"UnknownSopClassAccepted": false,
|
||||||
|
"DicomScpTimeout": 30,
|
||||||
|
|
||||||
|
"RemoteAccessAllowed": true,
|
||||||
|
"SslEnabled": false,
|
||||||
|
"SslCertificate": "certificate.pem",
|
||||||
|
"AuthenticationEnabled": false,
|
||||||
|
"RegisteredUsers": {
|
||||||
|
"test": "test"
|
||||||
|
},
|
||||||
|
"DicomModalities": {},
|
||||||
|
"DicomModalitiesInDatabase": false,
|
||||||
|
"DicomAlwaysAllowEcho": true,
|
||||||
|
"DicomAlwaysAllowStore": true,
|
||||||
|
"DicomCheckModalityHost": false,
|
||||||
|
"DicomScuTimeout": 10,
|
||||||
|
"OrthancPeers": {},
|
||||||
|
"OrthancPeersInDatabase": false,
|
||||||
|
"HttpProxy": "",
|
||||||
|
|
||||||
|
"HttpVerbose": true,
|
||||||
|
|
||||||
|
"HttpTimeout": 10,
|
||||||
|
"HttpsVerifyPeers": true,
|
||||||
|
"HttpsCACertificates": "",
|
||||||
|
"UserMetadata": {},
|
||||||
|
"UserContentType": {},
|
||||||
|
"StableAge": 60,
|
||||||
|
"StrictAetComparison": false,
|
||||||
|
"StoreMD5ForAttachments": true,
|
||||||
|
"LimitFindResults": 0,
|
||||||
|
"LimitFindInstances": 0,
|
||||||
|
"LimitJobs": 10,
|
||||||
|
"LogExportedResources": false,
|
||||||
|
"KeepAlive": true,
|
||||||
|
"TcpNoDelay": true,
|
||||||
|
"HttpThreadsCount": 50,
|
||||||
|
"StoreDicom": true,
|
||||||
|
"DicomAssociationCloseDelay": 5,
|
||||||
|
"QueryRetrieveSize": 10,
|
||||||
|
"CaseSensitivePN": false,
|
||||||
|
"LoadPrivateDictionary": true,
|
||||||
|
"Dictionary": {},
|
||||||
|
"SynchronousCMove": true,
|
||||||
|
"JobsHistorySize": 10,
|
||||||
|
"SaveJobs": true,
|
||||||
|
"OverwriteInstances": false,
|
||||||
|
"MediaArchiveSize": 1,
|
||||||
|
"StorageAccessOnFind": "Always",
|
||||||
|
"MetricsEnabled": true,
|
||||||
|
|
||||||
|
"DicomWeb": {
|
||||||
|
"Enable": true,
|
||||||
|
"Root": "/dicom-web/",
|
||||||
|
"EnableWado": true,
|
||||||
|
"WadoRoot": "/wado",
|
||||||
|
"Host": "127.0.0.1",
|
||||||
|
"Ssl": false,
|
||||||
|
"StowMaxInstances": 10,
|
||||||
|
"StowMaxSize": 10,
|
||||||
|
"QidoCaseSensitive": false
|
||||||
|
}
|
||||||
|
}
|
||||||
45
docker/OpenResty-Orthanc/docker-compose.yml
Normal file
45
docker/OpenResty-Orthanc/docker-compose.yml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Reference:
|
||||||
|
# - https://docs.docker.com/compose/compose-file
|
||||||
|
# - https://eclipsesource.com/blogs/2018/01/11/authenticating-reverse-proxy-with-keycloak/
|
||||||
|
|
||||||
|
version: '3.5'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Exposed server that's handling incoming web requests
|
||||||
|
# Underlying image: openresty/openresty:alpine-fat
|
||||||
|
ohif_viewer:
|
||||||
|
build:
|
||||||
|
# Project root
|
||||||
|
context: ./../../
|
||||||
|
# Relative to context
|
||||||
|
dockerfile: ./docker/OpenResty-Orthanc/dockerfile
|
||||||
|
image: webapp:latest
|
||||||
|
container_name: webapp
|
||||||
|
volumes:
|
||||||
|
# Nginx config
|
||||||
|
- ./config/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro
|
||||||
|
# Logs
|
||||||
|
- ./logs/nginx:/var/logs/nginx
|
||||||
|
# Let's Encrypt
|
||||||
|
# - letsencrypt_certificates:/etc/letsencrypt
|
||||||
|
# - letsencrypt_challenges:/var/www/letsencrypt
|
||||||
|
ports:
|
||||||
|
- '443:443' # SSL
|
||||||
|
- '80:80' # Web
|
||||||
|
depends_on:
|
||||||
|
- orthanc
|
||||||
|
restart: on-failure
|
||||||
|
|
||||||
|
# LINK: https://hub.docker.com/r/jodogne/orthanc-plugins/
|
||||||
|
# TODO: Update to use Postgres
|
||||||
|
# https://github.com/mrts/docker-postgresql-multiple-databases
|
||||||
|
orthanc:
|
||||||
|
image: jodogne/orthanc-plugins:1.5.6
|
||||||
|
hostname: orthanc
|
||||||
|
container_name: orthanc
|
||||||
|
volumes:
|
||||||
|
# Config
|
||||||
|
- ./config/orthanc.json:/etc/orthanc/orthanc.json:ro
|
||||||
|
# Persist data
|
||||||
|
- ./volumes/orthanc-db/:/var/lib/orthanc/db/
|
||||||
|
restart: unless-stopped
|
||||||
65
docker/OpenResty-Orthanc/dockerfile
Normal file
65
docker/OpenResty-Orthanc/dockerfile
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# docker-compose
|
||||||
|
# --------------
|
||||||
|
# This dockerfile is used by the `docker-compose.yml` adjacent file. When
|
||||||
|
# running `docker-compose build`, this dockerfile helps build the "webapp" image.
|
||||||
|
# All paths are relative to the `context`, which is the project root directory.
|
||||||
|
#
|
||||||
|
# docker build
|
||||||
|
# --------------
|
||||||
|
# If you would like to use this dockerfile to build and tag an image, make sure
|
||||||
|
# you set the context to the project's root directory:
|
||||||
|
# https://docs.docker.com/engine/reference/commandline/build/
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# SUMMARY
|
||||||
|
# --------------
|
||||||
|
# This dockerfile has two stages:
|
||||||
|
#
|
||||||
|
# 1. Building the React application for production
|
||||||
|
# 2. Setting up our Nginx (OpenResty*) image w/ step one's output
|
||||||
|
#
|
||||||
|
# * OpenResty is functionally identical to Nginx with the addition of Lua out of
|
||||||
|
# the box.
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 1: Build the application
|
||||||
|
FROM node:11.2.0-slim as builder
|
||||||
|
|
||||||
|
RUN mkdir /usr/src/app
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
ENV REACT_APP_CONFIG=config/docker_openresty-orthanc.js
|
||||||
|
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
||||||
|
|
||||||
|
COPY package.json /usr/src/app/package.json
|
||||||
|
COPY yarn.lock /usr/src/app/yarn.lock
|
||||||
|
|
||||||
|
ADD . /usr/src/app/
|
||||||
|
RUN yarn install
|
||||||
|
RUN yarn run build:web
|
||||||
|
|
||||||
|
# Stage 2: Bundle the built application into a Docker container
|
||||||
|
# which runs openresty (nginx) using Alpine Linux
|
||||||
|
# LINK: https://hub.docker.com/r/openresty/openresty
|
||||||
|
FROM openresty/openresty:1.15.8.1rc1-0-alpine-fat
|
||||||
|
|
||||||
|
RUN mkdir /var/log/nginx
|
||||||
|
RUN apk add --no-cache openssl
|
||||||
|
RUN apk add --no-cache openssl-dev
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
RUN apk add --no-cache gcc
|
||||||
|
# !!!
|
||||||
|
RUN luarocks install lua-resty-openidc
|
||||||
|
|
||||||
|
#
|
||||||
|
RUN luarocks install lua-resty-jwt
|
||||||
|
RUN luarocks install lua-resty-session
|
||||||
|
RUN luarocks install lua-resty-http
|
||||||
|
# !!!
|
||||||
|
RUN luarocks install lua-resty-openidc
|
||||||
|
RUN luarocks install luacrypto
|
||||||
|
|
||||||
|
# Copy build output to image
|
||||||
|
COPY --from=builder /usr/src/app/build /var/www/html
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/openresty/nginx/sbin/nginx", "-g", "daemon off;"]
|
||||||
2
docker/OpenResty-Orthanc/volumes/orthanc-db/.gitignore
vendored
Normal file
2
docker/OpenResty-Orthanc/volumes/orthanc-db/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
BIN
docs/latest/assets/designs/nginx-image-archive.fig
Normal file
BIN
docs/latest/assets/designs/nginx-image-archive.fig
Normal file
Binary file not shown.
BIN
docs/latest/assets/designs/scope-of-project.fig
Normal file
BIN
docs/latest/assets/designs/scope-of-project.fig
Normal file
Binary file not shown.
BIN
docs/latest/assets/img/nginx-image-archive.png
Normal file
BIN
docs/latest/assets/img/nginx-image-archive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/latest/assets/img/scope-of-project.png
Normal file
BIN
docs/latest/assets/img/scope-of-project.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
@ -4,18 +4,23 @@
|
|||||||
|
|
||||||
Fork the repository, make your change and submit a pull request.
|
Fork the repository, make your change and submit a pull request.
|
||||||
|
|
||||||
|
- The OHIF Viewer consists of code from three different repositories. Make sure
|
||||||
|
your change is modifying the appropriate one:
|
||||||
|
- `ohif-core`: Business Logic
|
||||||
|
- `react-viewerbase`: Reusable React Component Library
|
||||||
|
- `Viewers`: The glue, PWA, and primary extension point
|
||||||
|
- At a minimum, you may want to read the following documentation:
|
||||||
|
- [Essentials: Getting Started](./essentials/getting-started.md)
|
||||||
|
- [Advanced: Architecture](./advanced/architecture.md)
|
||||||
|
|
||||||
## Any guidance on submitting changes?
|
## Any guidance on submitting changes?
|
||||||
|
|
||||||
While we do appreciate code contributions, triaging and integrating contributed
|
While we do appreciate code contributions, triaging and integrating contributed
|
||||||
code changes can be very time consuming. Please consider the following tips when
|
code changes can be very time consuming. Please consider the following tips when
|
||||||
working on your pull requests:
|
working on your pull requests:
|
||||||
|
|
||||||
- Functionality is appropriate for the repository. Consider posting on the forum
|
- Functionality is appropriate for the repository. Consider creating a GitHub
|
||||||
if you are not sure.
|
issue to discuss your suggested changes.
|
||||||
- Code quality is acceptable. We don't have coding standards defined, but make
|
|
||||||
sure it passes ESLint and looks like the rest of the code in the repository.
|
|
||||||
- Quality of design is acceptable. This is a bit subjective so you should
|
|
||||||
consider posting on the forum for specific guidance.
|
|
||||||
- The scope of the pull request is not too large. Please consider separate pull
|
- The scope of the pull request is not too large. Please consider separate pull
|
||||||
requests for each feature as big pull requests are very time consuming to
|
requests for each feature as big pull requests are very time consuming to
|
||||||
understand.
|
understand.
|
||||||
@ -35,14 +40,14 @@ Replacing the number 237 in the link below with your pull request number should
|
|||||||
let you test it as well and you can use this link for discussions on github
|
let you test it as well and you can use this link for discussions on github
|
||||||
without requiring reviewers to download and build your branch.
|
without requiring reviewers to download and build your branch.
|
||||||
|
|
||||||
```
|
```bash
|
||||||
https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
|
https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
|
||||||
```
|
```
|
||||||
|
|
||||||
If you have made a documentation change, a link like this will let you preview
|
If you have made a documentation change, a link like this will let you preview
|
||||||
the gitbook generated by the pull request:
|
the gitbook generated by the pull request:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
https://deploy-preview-237--ohif.netlify.com/contributing.html
|
https://deploy-preview-237--ohif.netlify.com/contributing.html
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
4
docs/latest/deployment/_nginx-image-archive-diagram.md
Normal file
4
docs/latest/deployment/_nginx-image-archive-diagram.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<div style="text-align: center;">
|
||||||
|
<img src="/assets/img/nginx-image-archive.png" alt="request flow example" style="margin: 0 auto;" />
|
||||||
|
<div><i>simplified request flow diagram</i></div>
|
||||||
|
</div>
|
||||||
@ -182,6 +182,7 @@ to secure access to your Image Archive as well.
|
|||||||
|
|
||||||
We've included a few recipes for common deployment scenarios. There are many,
|
We've included a few recipes for common deployment scenarios. There are many,
|
||||||
many possible configurations, so please don't feel limited to these setups.
|
many possible configurations, so please don't feel limited to these setups.
|
||||||
|
Please feel free to suggest or contribute your own recipes.
|
||||||
|
|
||||||
- Script Include
|
- Script Include
|
||||||
- [Embedding the Viewer](deployment/recipes/embedded-viewer.md)
|
- [Embedding the Viewer](deployment/recipes/embedded-viewer.md)
|
||||||
|
|||||||
@ -1 +1,245 @@
|
|||||||
# Nginx + Image Archive
|
# Nginx + Image Archive
|
||||||
|
|
||||||
|
> DISCLAIMER! We make no claims or guarantees of this approach's security. If in
|
||||||
|
> doubt, enlist the help of an expert and conduct proper audits.
|
||||||
|
|
||||||
|
At a certain point, you may want others to have access to your instance of the
|
||||||
|
OHIF Viewer and its medical imaging data. This post covers one of many potential
|
||||||
|
setups that accomplish that. Please note, noticably absent is user account
|
||||||
|
control.
|
||||||
|
|
||||||
|
Do not use this recipe to host sensitive medical data on the open web. Depending
|
||||||
|
on your company's policies, this may be an appropriate setup on an internal
|
||||||
|
network when protected with a server's basic authentication. For a more robust
|
||||||
|
setup, check out our [user account control recpie](./user-account-control.md)
|
||||||
|
that builds on the lessons learned here.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Our two biggest hurdles when hosting our image archive and web client are:
|
||||||
|
|
||||||
|
- Risks related to exposing our PACS to the netowrk
|
||||||
|
- Cross-Origin Resource Sharing (CORS) requests
|
||||||
|
|
||||||
|
### Handling Web Requests
|
||||||
|
|
||||||
|
We mittigate our first issue by allowing [Nginx][nginx] to handle incoming web
|
||||||
|
requests. Nginx is open source software for web serving, reverse proxying,
|
||||||
|
caching, and more. It's designed for maximum performance and stability --
|
||||||
|
allowing us to more reliably serve content than Orthanc's built-in server can.
|
||||||
|
|
||||||
|
More specifically, we accomplish this by using a
|
||||||
|
[`reverse proxy`](https://en.wikipedia.org/wiki/Reverse_proxy) to retrieve
|
||||||
|
resources from our image archive (Orthanc), and when accessing its web admin.
|
||||||
|
|
||||||
|
> A reverse proxy is a type of proxy server that retrieves resources on behalf
|
||||||
|
> of a client from one or more servers. These resources are then returned to the
|
||||||
|
> client, appearing as if they originated from the proxy server itself.
|
||||||
|
|
||||||
|
### CORS Issues
|
||||||
|
|
||||||
|
Cross-Origin Resource Sharing (CORS) is a mechanism that uses HTTP headers to
|
||||||
|
tell a browser which web applications have permission to access selected
|
||||||
|
resources from a server at a different origin (domain, protocol, port). IE. By
|
||||||
|
default, a Web App located at `http://my-website.com` can't access resources
|
||||||
|
hosted at `http://not-my-website.com`
|
||||||
|
|
||||||
|
We can solve this one of two ways:
|
||||||
|
|
||||||
|
1. Have our Image Archive located at the same domain as our Web App
|
||||||
|
2. Add appropriate `Access-Control-Allow-*` HTTP headers
|
||||||
|
|
||||||
|
This solution uses the first approach, but you can see an example of the second
|
||||||
|
in the `docker-compose` bundled with this project for local development:
|
||||||
|
[HERE](#)
|
||||||
|
|
||||||
|
You can read more about CORS in this Medium article: [Understanding
|
||||||
|
CORS][understanding-cors]
|
||||||
|
|
||||||
|
### Diagram
|
||||||
|
|
||||||
|
This setup allows us to create a setup similar to the one pictured below:
|
||||||
|
|
||||||
|
{% include "./../_nginx-image-archive-diagram.md" %}
|
||||||
|
|
||||||
|
- All web requests are routed through `nginx` on our `OpenResty` image
|
||||||
|
- `/pacs` is a reverse proxy for `orthanc`'s `DICOM Web` endpoints
|
||||||
|
- `/pacs-admin` is a reverse proxy for `orthanc`'s Web Admin
|
||||||
|
- All static resources for OHIF Viewer are served up by `nginx` when a matching
|
||||||
|
route for that resource is requested
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Docker
|
||||||
|
- [Docker for Mac](https://docs.docker.com/docker-for-mac/)
|
||||||
|
- [Docker for Windows](https://docs.docker.com/docker-for-windows/)
|
||||||
|
|
||||||
|
_Not sure if you have `docker` installed already? Try running `docker --version`
|
||||||
|
in command prompt or terminal_
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
_Spin Things Up_
|
||||||
|
|
||||||
|
- Navigate to `<project-root>/docker/OpenResty-Orthanc` in your shell
|
||||||
|
- Run `docker-compose up`
|
||||||
|
|
||||||
|
_Upload Your First Study_
|
||||||
|
|
||||||
|
- Navigate to `http://127.0.0.1/pacs-admin`
|
||||||
|
- From the top right, select "Upload"
|
||||||
|
- Click "Select files to upload..." (DICOM)
|
||||||
|
- Click "Start the upload"
|
||||||
|
- Navigate back to `http://127.0.0.1/` to view your studies in the Study List
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
_Exit code 137_
|
||||||
|
|
||||||
|
This means Docker ran out of memory. Open Docker Desktop, go to the `advanced`
|
||||||
|
tab, and increase the amount of Memory available.
|
||||||
|
|
||||||
|
_Cannot create container for service X_
|
||||||
|
|
||||||
|
Use this one with caution: `docker system prune`
|
||||||
|
|
||||||
|
_X is already running_
|
||||||
|
|
||||||
|
Stop running all containers:
|
||||||
|
|
||||||
|
- Win: `docker ps -a -q | ForEach { docker stop $_ }`
|
||||||
|
- Linux: `docker stop $(docker ps -a -q)`
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
After verifying that everything runs with default configuration values, you will
|
||||||
|
likely want to update:
|
||||||
|
|
||||||
|
- The domain: `http://127.0.0.1`
|
||||||
|
|
||||||
|
#### OHIF Viewer
|
||||||
|
|
||||||
|
The OHIF Viewer's configuration is imported from a static `.js` file and made
|
||||||
|
available globally at `window.config`. The configuration we use is set to a
|
||||||
|
specific file when we build the viewer, and determined by the env variable:
|
||||||
|
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
|
||||||
|
this solution:
|
||||||
|
|
||||||
|
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc.js`
|
||||||
|
|
||||||
|
You can find the configuration we're using here:
|
||||||
|
`/public/config/docker_openresty-orthanc.js`
|
||||||
|
|
||||||
|
To rebuild the `webapp` image created by our `dockerfile` after updating the
|
||||||
|
Viewer's configuration, you can run:
|
||||||
|
|
||||||
|
- `docker-compose build` OR
|
||||||
|
- `docker-compose up --build`
|
||||||
|
|
||||||
|
#### Other
|
||||||
|
|
||||||
|
All other files are found in: `/docker/OpenResty-Orthanc/`
|
||||||
|
|
||||||
|
| Service | Configuration | Docs |
|
||||||
|
| ----------------- | ---------------------------------------------- | ------------------------------------------- |
|
||||||
|
| OHIF Viewer | [dockerfile][dockerfile] / [config.js][config] | You're reading them now! |
|
||||||
|
| OpenResty (Nginx) | [`/nginx.conf`][config-nginx] | [lua-resty-openidc][lua-resty-openidc-docs] |
|
||||||
|
| Orthanc | [`/orthanc.json`][config-orthanc] | [Here][orthanc-docs] |
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
### Deploying to Production
|
||||||
|
|
||||||
|
While these configuration and docker-compose files model an environment suitable
|
||||||
|
for production, they are not easy to deploy "as is". You can either:
|
||||||
|
|
||||||
|
- Manually recreate this environment and deploy built application files **OR**
|
||||||
|
- Deploy to a cloud kubernetes provider like
|
||||||
|
[Digital Ocean](https://www.digitalocean.com/products/kubernetes/) **OR**
|
||||||
|
- [See a full list of cloud providers here](https://landscape.cncf.io/category=cloud&format=card-mode&grouping=category)
|
||||||
|
- Find and follow your preferred provider's guide on setting up
|
||||||
|
[swarms and stacks](https://docs.docker.com/get-started/)
|
||||||
|
|
||||||
|
### Adding SSL
|
||||||
|
|
||||||
|
Adding SSL registration and renewal for your domain with Let's Encrypt that
|
||||||
|
terminates at Nginx is an incredibly important step toward securing your data.
|
||||||
|
Here are some resources, specific to this setup, that may be helpful:
|
||||||
|
|
||||||
|
- [lua-resty-auto-ssl](https://github.com/GUI/lua-resty-auto-ssl)
|
||||||
|
- [Let's Encrypt + Nginx](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/)
|
||||||
|
|
||||||
|
While we terminate SSL at Nginx, it may be worth using self signed certificates
|
||||||
|
for communication between services.
|
||||||
|
|
||||||
|
- [SSL Termination for TCP Upstream Servers](https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/)
|
||||||
|
|
||||||
|
### Use PostgresSQL w/ Orthanc
|
||||||
|
|
||||||
|
Orthanc can handle a large amount of data and requests, but if you find that
|
||||||
|
requests start to slow as you add more and more studies, you may want to
|
||||||
|
configure your Orthanc instance to use PostgresSQL. Instructions on how to do
|
||||||
|
that can be found in the
|
||||||
|
[`Orthanc Server Book`](http://book.orthanc-server.com/users/docker.html), under
|
||||||
|
"PostgreSQL and Orthanc inside Docker"
|
||||||
|
|
||||||
|
### Improving This Guide
|
||||||
|
|
||||||
|
Here are some improvements this guide would benefit from, and that we would be
|
||||||
|
more than happy to accept Pull Requests for:
|
||||||
|
|
||||||
|
- SSL Support
|
||||||
|
- Complete configuration with `.env` file (or something similar)
|
||||||
|
- Any security issues
|
||||||
|
- One-click deploy to a cloud provider
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
### Misc. Helpful Commands
|
||||||
|
|
||||||
|
_Check if `nginx.conf` is valid:_
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -t -a stdout --name my-openresty -v $PWD/config/:/usr/local/openresty/nginx/conf/:ro openresty/openresty:alpine-fat openresty -c /usr/local/openresty/nginx/conf/nginx.conf -t
|
||||||
|
```
|
||||||
|
|
||||||
|
_Interact w/ running container:_
|
||||||
|
|
||||||
|
`docker exec -it CONTAINER_NAME bash`
|
||||||
|
|
||||||
|
_List running containers:_
|
||||||
|
|
||||||
|
`docker ps`
|
||||||
|
|
||||||
|
### Referenced Articles
|
||||||
|
|
||||||
|
For more documentation on the software we've chosen to use, you may find the
|
||||||
|
following resources helpful:
|
||||||
|
|
||||||
|
- [Orthanc for Docker](http://book.orthanc-server.com/users/docker.html)
|
||||||
|
- [OpenResty Guide](http://www.staticshin.com/programming/definitely-an-open-resty-guide/)
|
||||||
|
- [Lua Ngx API](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/)
|
||||||
|
|
||||||
|
For a different take on this setup, check out the repository one of our
|
||||||
|
community members put together:
|
||||||
|
|
||||||
|
- [mjstealey/ohif-orthanc-dimse-docker](https://github.com/mjstealey/ohif-orthanc-dimse-docker)
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Links
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
<!-- DOCS -->
|
||||||
|
[nginx]: https://www.nginx.com/resources/glossary/nginx/
|
||||||
|
[understanding-cors]: https://medium.com/@baphemot/understanding-cors-18ad6b478e2b
|
||||||
|
[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
|
||||||
|
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc
|
||||||
|
<!-- SRC -->
|
||||||
|
[config]: #
|
||||||
|
[dockerfile]: #
|
||||||
|
[config-nginx]: #
|
||||||
|
[config-orthanc]: #
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
|
|||||||
@ -1 +1,66 @@
|
|||||||
# Scope of Project
|
# Scope of Project
|
||||||
|
|
||||||
|
The OHIF Viewer is a web based medical imaging viewer. This allows it to be used
|
||||||
|
on almost any device, anywhere. The OHIF Viewer is what is commonly reffered to
|
||||||
|
as a ["Dumb Client"][simplicable]
|
||||||
|
|
||||||
|
> A dumb client is software that fully depends on a connection to a server or
|
||||||
|
> cloud service for its functionality. Without a network connection, the
|
||||||
|
> software offers nothing useful. - [simplicable.com][simplicable]
|
||||||
|
|
||||||
|
While the Viewer persists some data, it's scope is limited to caching things
|
||||||
|
like user preferences and previous query paramaters. Because of this, the Viewer
|
||||||
|
has been built to be highly configurable to work with almost any web accessible
|
||||||
|
data source.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
To be more specific, the OHIF Viewer is a collection of HTML, JS, and CSS files.
|
||||||
|
These can be delivered to your end users however you would like:
|
||||||
|
|
||||||
|
- From the local networok
|
||||||
|
- From a remote web server
|
||||||
|
- From a CDN (content delivery network)
|
||||||
|
- From a service-worker's cache
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
These "static asset" files are referred to collectively as a "Progressive Web
|
||||||
|
Application" (PWA), and have the same capabilities and limitations that all PWAs
|
||||||
|
have.
|
||||||
|
|
||||||
|
All studies, series, images, imageframes, metadata, and the images themselves
|
||||||
|
must come from an external source. There are many, many ways to provide this
|
||||||
|
information, the OHIF Viewer's scope **DOES NOT** encompass providing _any_
|
||||||
|
data; only the configuration necessary to interface with one or more of these
|
||||||
|
many data sources. The OHIF Viewer's scope **DOES** include configuration and
|
||||||
|
support for services that are protected with OpenID-Connect.
|
||||||
|
|
||||||
|
In an effort to aide our users and contributors, we attempt to provide several
|
||||||
|
[deployment and hosting recipes](./../deployment/index.md) as potential starting
|
||||||
|
points. These are not meant to be rock solid, production ready, solutions; like
|
||||||
|
most recipes, they should be augmented to best fit you and your organization's
|
||||||
|
taste, preferences, etc.
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
_Am I able to cache studies for offline viewing?_
|
||||||
|
|
||||||
|
Not currently. A web page's offline cache capabilities are limited and somewhat
|
||||||
|
volatile (mostly imposed at the browser vendor level). For more robust offline
|
||||||
|
caching, you may want to consider a server on the local network, or packaging
|
||||||
|
the OHIF Viewer as a desktop application.
|
||||||
|
|
||||||
|
_Does the OHIF Viewer work with the local filesystem?_
|
||||||
|
|
||||||
|
It is possible to accomplish this through extensions; however, for an user
|
||||||
|
experience that accomodates a large number of studies, you would likely need to
|
||||||
|
package the OHIF Viewer as an [Electron app][electron].
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Links
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
[simplicable]: https://simplicable.com/new/dumb-client
|
||||||
|
[electron]: https://electronjs.org/
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
|
|||||||
@ -4,16 +4,14 @@
|
|||||||
|
|
||||||
We accept and triage bug reports through Github primarily.
|
We accept and triage bug reports through Github primarily.
|
||||||
|
|
||||||
1. [Create a Github account](https://github.com/join)
|
- [Create a Github account](https://github.com/join)
|
||||||
2. Search the current [Issue List](https://github.com/OHIF/Viewers/issues) to
|
- Search the current [Issue List](https://github.com/OHIF/Viewers/issues) to
|
||||||
ensure you are not creating a duplicate issue.
|
ensure you are not creating a duplicate issue.
|
||||||
|
- If your issue already exists, post a comment to show us that this issue also
|
||||||
If your issue already exists, post a comment to show us that this issue also
|
affects you.
|
||||||
affects you.
|
- If no prior issue exists,
|
||||||
|
[Create a New Issue](https://github.com/OHIF/Viewers/issues/new) on the
|
||||||
3. If no prior issue exists,
|
repository.
|
||||||
[Create a New Issue](https://github.com/OHIF/Viewers/issues/new) on the
|
|
||||||
repository.
|
|
||||||
|
|
||||||
Some tips for filing a new issue:
|
Some tips for filing a new issue:
|
||||||
|
|
||||||
|
|||||||
26
public/config/docker_openresty-orthanc.js
Normal file
26
public/config/docker_openresty-orthanc.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
window.config = {
|
||||||
|
routerBasename: '/',
|
||||||
|
relativeWebWorkerScriptsPath: '',
|
||||||
|
servers: {
|
||||||
|
// This is an array, but we'll only use the first entry for now
|
||||||
|
dicomWeb: [
|
||||||
|
{
|
||||||
|
name: 'Orthanc',
|
||||||
|
wadoUriRoot: 'http://127.0.0.1/pacs/wado',
|
||||||
|
qidoRoot: 'http://127.0.0.1/pacs/dicom-web',
|
||||||
|
wadoRoot: 'http://127.0.0.1/pacs/dicom-web',
|
||||||
|
qidoSupportsIncludeField: false,
|
||||||
|
imageRendering: 'wadors',
|
||||||
|
thumbnailRendering: 'wadors',
|
||||||
|
// REQUIRED TAG:
|
||||||
|
// https://github.com/OHIF/ohif-core/blob/59e1e04b92be24aee5d4402445cb3dcedb746995/src/studies/retrieveStudyMetadata.js#L54
|
||||||
|
// TODO: Remove tag after https://github.com/OHIF/ohif-core/pull/19 is merged and we bump version
|
||||||
|
requestOptions: {
|
||||||
|
// undefined to use JWT + Bearer auth
|
||||||
|
// auth: 'orthanc:orthanc',
|
||||||
|
requestFromBrowser: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user