From d10710ec51605c4a4803001defb3eabcaef6b1a5 Mon Sep 17 00:00:00 2001 From: dannyrb Date: Mon, 13 May 2019 13:14:08 -0400 Subject: [PATCH] Copy-pasta and trim --- docker/OpenResty-Orthanc/.dockerignore | 16 +++ docker/OpenResty-Orthanc/.env | 5 + docker/OpenResty-Orthanc/config/nginx.conf | 135 ++++++++++++++++++ docker/OpenResty-Orthanc/config/orthanc.json | 89 ++++++++++++ docker/OpenResty-Orthanc/docker-compose.yml | 45 ++++++ docker/OpenResty-Orthanc/dockerfile | 65 +++++++++ .../volumes/orthanc-db/.gitignore | 2 + public/config/docker_openresty-orthanc.js | 26 ++++ 8 files changed, 383 insertions(+) create mode 100644 docker/OpenResty-Orthanc/.dockerignore create mode 100644 docker/OpenResty-Orthanc/.env create mode 100644 docker/OpenResty-Orthanc/config/nginx.conf create mode 100644 docker/OpenResty-Orthanc/config/orthanc.json create mode 100644 docker/OpenResty-Orthanc/docker-compose.yml create mode 100644 docker/OpenResty-Orthanc/dockerfile create mode 100644 docker/OpenResty-Orthanc/volumes/orthanc-db/.gitignore create mode 100644 public/config/docker_openresty-orthanc.js diff --git a/docker/OpenResty-Orthanc/.dockerignore b/docker/OpenResty-Orthanc/.dockerignore new file mode 100644 index 000000000..67f1b2e98 --- /dev/null +++ b/docker/OpenResty-Orthanc/.dockerignore @@ -0,0 +1,16 @@ +# Output +dist/ + +# Dependencies +node_modules/ + +# Root +README.md +Dockerfile + +# Misc. Config +.git +.DS_Store +.gitignore +.vscode +.circleci diff --git a/docker/OpenResty-Orthanc/.env b/docker/OpenResty-Orthanc/.env new file mode 100644 index 000000000..6989ff3fc --- /dev/null +++ b/docker/OpenResty-Orthanc/.env @@ -0,0 +1,5 @@ +# Docker ENV and ARG Variables +# ---------------------------- +# https://vsupalov.com/docker-arg-env-variable-guide/ +# +# diff --git a/docker/OpenResty-Orthanc/config/nginx.conf b/docker/OpenResty-Orthanc/config/nginx.conf new file mode 100644 index 000000000..777e49703 --- /dev/null +++ b/docker/OpenResty-Orthanc/config/nginx.conf @@ -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 { + # } + } +} diff --git a/docker/OpenResty-Orthanc/config/orthanc.json b/docker/OpenResty-Orthanc/config/orthanc.json new file mode 100644 index 000000000..2e10723c0 --- /dev/null +++ b/docker/OpenResty-Orthanc/config/orthanc.json @@ -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 + } +} diff --git a/docker/OpenResty-Orthanc/docker-compose.yml b/docker/OpenResty-Orthanc/docker-compose.yml new file mode 100644 index 000000000..0b6487c8a --- /dev/null +++ b/docker/OpenResty-Orthanc/docker-compose.yml @@ -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 diff --git a/docker/OpenResty-Orthanc/dockerfile b/docker/OpenResty-Orthanc/dockerfile new file mode 100644 index 000000000..6b96885cf --- /dev/null +++ b/docker/OpenResty-Orthanc/dockerfile @@ -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;"] diff --git a/docker/OpenResty-Orthanc/volumes/orthanc-db/.gitignore b/docker/OpenResty-Orthanc/volumes/orthanc-db/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/docker/OpenResty-Orthanc/volumes/orthanc-db/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/public/config/docker_openresty-orthanc.js b/public/config/docker_openresty-orthanc.js new file mode 100644 index 000000000..65ed5297f --- /dev/null +++ b/public/config/docker_openresty-orthanc.js @@ -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, + }, + }, + ], + }, +}