feat(Docker): Facilitate the ability to run the OHIF docker image over SSL (#3511)
This commit is contained in:
parent
ffd53eff85
commit
61595ce7d6
@ -1,5 +1,6 @@
|
||||
server {
|
||||
listen ${PORT};
|
||||
listen ${PORT} default_server;
|
||||
listen [::]:${PORT} default_server;
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
|
||||
22
.docker/Viewer-v3.x/default.ssl.conf.template
Normal file
22
.docker/Viewer-v3.x/default.ssl.conf.template
Normal file
@ -0,0 +1,22 @@
|
||||
server {
|
||||
listen ${SSL_PORT} ssl http2 default_server;
|
||||
listen [::]:${SSL_PORT} ssl http2 default_server;
|
||||
ssl_certificate /etc/ssl/certs/ssl-certificate.crt;
|
||||
ssl_certificate_key /etc/ssl/private/ssl-private-key.key;
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cross-Origin-Opener-Policy same-origin;
|
||||
add_header Cross-Origin-Embedder-Policy require-corp;
|
||||
add_header Cross-Origin-Resource-Policy same-origin;
|
||||
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 $http_x_forwarded_proto;
|
||||
}
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
envsubst '${PORT}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf
|
||||
if [ -n "$SSL_PORT" ]
|
||||
then
|
||||
envsubst '${SSL_PORT}:${PORT}' < /usr/src/default.ssl.conf.template > /etc/nginx/conf.d/default.conf
|
||||
else
|
||||
envsubst '${PORT}' < /usr/src/default.conf.template > /etc/nginx/conf.d/default.conf
|
||||
fi
|
||||
|
||||
if [ -n "$APP_CONFIG" ]
|
||||
then
|
||||
echo "$APP_CONFIG" > /usr/share/nginx/html/app-config.js
|
||||
fi
|
||||
|
||||
if [ -n "$CLIENT_ID" ] || [ -n "$HEALTHCARE_API_ENDPOINT" ]
|
||||
then
|
||||
|
||||
@ -61,7 +61,7 @@ RUN yarn run build
|
||||
|
||||
# Stage 3: Bundle the built application into a Docker container
|
||||
# which runs Nginx using Alpine Linux
|
||||
FROM nginxinc/nginx-unprivileged:1.23.1-alpine as final
|
||||
FROM nginxinc/nginx-unprivileged:1.25-alpine as final
|
||||
#RUN apk add --no-cache bash
|
||||
ENV PORT=80
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
@ -69,5 +69,10 @@ USER nginx
|
||||
COPY --chown=nginx:nginx .docker/Viewer-v3.x /usr/src
|
||||
RUN chmod 777 /usr/src/entrypoint.sh
|
||||
COPY --from=builder /usr/src/app/platform/app/dist /usr/share/nginx/html
|
||||
# In entrypoint.sh, app-config.js might be overwritten, so chmod it to be writeable.
|
||||
# The nginx user cannot chmod it, so change to root.
|
||||
USER root
|
||||
RUN chmod 666 /usr/share/nginx/html/app-config.js
|
||||
USER nginx
|
||||
ENTRYPOINT ["/usr/src/entrypoint.sh"]
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
platform/docs/docs/assets/img/cors-browser-console-errors.png
Normal file
BIN
platform/docs/docs/assets/img/cors-browser-console-errors.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
platform/docs/docs/assets/img/cors-network-panel-errors.png
Normal file
BIN
platform/docs/docs/assets/img/cors-network-panel-errors.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
platform/docs/docs/assets/img/ohif-non-secure-context.png
Normal file
BIN
platform/docs/docs/assets/img/ohif-non-secure-context.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 131 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
BIN
platform/docs/docs/assets/img/self-signed-cert-warning.png
Normal file
BIN
platform/docs/docs/assets/img/self-signed-cert-warning.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
sidebar_position: 5
|
||||
sidebar_label: Authorization
|
||||
---
|
||||
|
||||
|
||||
308
platform/docs/docs/deployment/cors.md
Normal file
308
platform/docs/docs/deployment/cors.md
Normal file
@ -0,0 +1,308 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# Cross-Origin Information for OHIF
|
||||
|
||||
This document describes various security configurations, settings and environments/contexts needed to fully leverage OHIF’s capabilities. One may need some configurations while others might need ALL of them - it all depends on the environment OHIF is expected to run in.
|
||||
|
||||
In particular, three of OHIF’s features depend on these configurations:
|
||||
- [OHIF’s use of SharedArrayBuffer](#sharedarraybuffer)
|
||||
- [Embedding OHIF in an iframe](#embedding-ohif-in-an-iframe)
|
||||
- [XMLHttpRequests to fetch data from data sources](#cors-in-ohif)
|
||||
|
||||
|
||||
## SharedArrayBuffer
|
||||
A `SharedArrayBuffer` is a JavaScript object that is similar to an `ArrayBuffer` but can be shared between web workers and the window that spawned them via the `postMessage` API. See [SharedArrayBuffer in MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) for more information.
|
||||
|
||||
### Security Requirements
|
||||
|
||||
In order to use `SharedArrayBuffer` objects in the browser, the following security conditions must be met:
|
||||
|
||||
- The page must be served in a [secure context](#secure-context).
|
||||
- The page must have [cross-origin isolation](#cross-origin-isolation) enabled.
|
||||
|
||||
### `SharedArrayBuffer` in OHIF
|
||||
|
||||
OHIF uses `SharedArrayBuffer` in its volume loader (from Cornerstone3D). It comes with the benefit of improved performance and optimization at the cost of some configuration to use it.
|
||||
|
||||
As such, if the following popup is shown when launching OHIF then the OHIF server will have to be configured to permit the loading of volumetric images and data. Note that stack viewports are still available and functional even when this error is present.
|
||||
|
||||

|
||||
|
||||
To better determine which (if not all) of the [security requirements](#security-requirements) are lacking, have a look at the browser console.
|
||||
|
||||
Output in the console similar to the following indicates that OHIF is not running in a [secure context](#secure-context).
|
||||
|
||||

|
||||
|
||||
Absence of the above error in the console together with the presence of the Cross Origin Isolation popup warning, likely indicates that either or both of the [COOP](#coop---cross-origin-opener-policy) and/or [COEP](#coep---cross-origin-embedder-policy) headers are not set for OHIF.
|
||||
|
||||
## Embedding OHIF in an iframe
|
||||
|
||||
As described [here](./iframe.md), there are cases where OHIF will be embedded in an iframe. The following links provide more information for setting up and configuring OHIF to work in an iframe:
|
||||
|
||||
- [OHIF iframe documentation](./iframe.md#static-build)
|
||||
- [OHIF as a Cross-origin Resource in an iframe](#ohif-as-a-cross-origin-resource-in-an-iframe)
|
||||
|
||||
## Secure Context
|
||||
|
||||
MDN defines a secure context as [“a Window or Worker for which certain minimum standards of authentication and confidentiality are met.“](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts)
|
||||
|
||||
Any local URL is considered secure. The following are some examples of local URLs that are considered secure…
|
||||
- http://localhost
|
||||
- http://127.0.0.1:3000
|
||||
|
||||
URLs that are NOT local must be delivered over `https://` or `wss://` (i.e. TLS) to be considered secure. See [When is a context considered secure](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure) in MDN for more information.
|
||||
|
||||
### iframes
|
||||
|
||||
A page embedded in an iframe is considered secure if it itself and every one of its embedding ancestors are delivered securely. Otherwise it is deemed insecure.
|
||||
|
||||
### Why does OHIF require a secure context?
|
||||
|
||||
Beyond all of the inherent benefits of a secure connection, OHIF requires a secure context so that it can utilize [SharedArrayBuffer](#sharedarraybuffer) objects for volume rendering.
|
||||
|
||||
### Configuring/setting up a secure context
|
||||
|
||||
[Local URLs are considered secure](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure), and as such whenever OHIF is accessed via a local URL (e.g. http://localhost:3000) it is running in a secure context. For example, in a development environment using the default webpack setup, OHIF can be deployed and accessed in a secure context at http://localhost:3000.
|
||||
|
||||
The best alternative is to host OHIF over HTTPS.
|
||||
|
||||
:::tip
|
||||
OHIF can be served over HTTPS in a variety of ways (these are just some examples).
|
||||
- Website hosting services that offer HTTPS deployment (e.g,. Netlify) or offer HTTPS load balancers (AWS, Google Cloud etc.)
|
||||
- Setting up a reverse proxy (e.g. `nginx`) with a self-signed certificate that forwards requests to the OHIF server
|
||||
- [An OHIF Docker image can be set up this way](./docker.md#ssl).
|
||||
:::
|
||||
|
||||
## Origin Definition
|
||||
|
||||
According to [MDN](https://developer.mozilla.org/en-US/docs/Glossary/Origin), a Web content’s origin is defined by the scheme (protocol), hostname (domain), and port of the URL used to access it. Two objects have the same origin only when the scheme, hostname, and port all match.
|
||||
|
||||
## CORS - Cross-Origin Resource Sharing
|
||||
|
||||
A cross-origin resource is a resource (e.g. image, JSON, etc) that is served by one origin and used/referenced by a different origin.
|
||||
|
||||
CORS is the protocol utilized by web servers and browsers whereby a server of one origin identifies and/or restricts which of its resources that other origins (i.e. other than its own) a browser should allow access to. By default a browser does not permit cross-origin resource sharing.
|
||||
|
||||
The CORS mechanism relies on the HTTP response headers from the server to indicate if a resource can be shared with a different origin.
|
||||
|
||||
See the [MDN CORS article](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) for more information.
|
||||
|
||||
### CORS HTTP Headers
|
||||
|
||||
The header that mostly concerns OHIF is listed below and should be configured accordingly on the DICOMweb server or any data source that OHIF would make XMLHttpRequests to for its data.
|
||||
|
||||
```http
|
||||
Access-Control-Allow-Origin: `<origin>` | *
|
||||
```
|
||||
|
||||
:::tip
|
||||
The `Access-Control-Allow-Origin` header specifies which origins can access the served resource embedded in the response.
|
||||
|
||||
Either a single, specific origin (i.e. `<origin>`) can be specified or ALL origins (i.e. *)
|
||||
|
||||
See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#access-control-allow-origin) for more information.
|
||||
:::
|
||||
|
||||
### CORS in OHIF
|
||||
|
||||
OHIF fetches and displays data and images from data sources. It invokes XMLHttpRequests to some data sources such as DICOMweb data sources to fetch the information to render. Typically, a DICOMweb server is hosted on a completely different origin than the one serving OHIF. As such, those XMLHttpRequests use CORS.
|
||||
|
||||
### Troubleshooting CORS in OHIF
|
||||
|
||||
The following is an example screenshot of the browser console when one of OHIF’s DICOMweb data source servers is not configured for CORS.
|
||||
|
||||

|
||||
|
||||
And the following is what is in the accompanying network tab.
|
||||
|
||||

|
||||
|
||||
:::info
|
||||
Setting the appropriate CORS header varies per server or service that is hosting the data source. What follows below is just one example to remedy the problem.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If Orthanc is the data source running in a Docker container composed with/behind nginx. And OHIF is being served at localhost:3000. The issue can be remedied by adding either of the following to Orthanc’s Docker container nginx.conf file.
|
||||
|
||||
```nginx
|
||||
add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
|
||||
```
|
||||
|
||||
Or
|
||||
|
||||
```nginx
|
||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
||||
```
|
||||
:::
|
||||
|
||||
## COOP - Cross-Origin Opener Policy
|
||||
|
||||
The COOP HTTP response header restricts the global, root document of the page from being referenced and accessed by another cross-origin document that might open the page in a window. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy) for more information.
|
||||
|
||||
### Header Values Pertinent to OHIF (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy#syntax) for more information)
|
||||
|
||||
|Value|Description|
|
||||
|-----|-----------|
|
||||
|same-origin|Restricts the document to be referenced by openers of the same origin only.|
|
||||
|
||||
### COOP in OHIF
|
||||
|
||||
COOP is required for [SharedArrayBuffer](#sharedarraybuffer) usage in OHIF. See also [Troubleshooting Cross-origin Isolation in OHIF](#troubleshooting-cross-origin-isolation-in-ohif).
|
||||
|
||||
## COEP - Cross-Origin Embedder Policy
|
||||
|
||||
The COEP HTTP response header restricts cross-origin documents from being embedded into a document (e.g. in an iframe, video, image, etc). See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy) for more information.
|
||||
|
||||
### Header Values Pertinent to OHIF (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy#syntax) for more information)
|
||||
|
||||
|Value|Description|
|
||||
|-----|-----------|
|
||||
|require-corp|Permits the document to load either of the following embedded resources: <ul><li>Those from the same origin</li><li>Cross-origin resources embedded by a DOM element that has the appropriate [crossorigin attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) set</li><li>Cross-origin resources with the appropriate [CORP response header](#corp---cross-origin-resource-policy)</li></ul>
|
||||
|credentialless|See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy#syntax) for more information|
|
||||
|
||||
### COEP in OHIF
|
||||
|
||||
COEP is required for [SharedArrayBuffer](#sharedarraybuffer) usage in OHIF. See also [Troubleshooting Cross-origin Isolation in OHIF](#troubleshooting-cross-origin-isolation-in-ohif).
|
||||
|
||||
## Cross-origin Isolation
|
||||
|
||||
Cross-origin isolation is [enabled](https://web.dev/cross-origin-isolation-guide/#enable-cross-origin-isolation) for a web page when the following COOP and COEP headers are set.
|
||||
- [COOP](#coop---cross-origin-opener-policy) with `same-origin`
|
||||
- [COEP](#coep---cross-origin-embedder-policy) with `require-corp` or `credentialless`
|
||||
|
||||
### iframe
|
||||
|
||||
An iframe is considered to have cross-origin isolation enabled if it itself has the appropriate COOP and COEP headers set as well as every one of its embedding ancestors.
|
||||
|
||||
### Troubleshooting Cross-origin Isolation in OHIF
|
||||
|
||||
The [SharedArrayBuffer in OHIF](#sharedarraybuffer-in-ohif) section describes how to determine if there are problems with cross-origin isolation in OHIF. If it is determined that COOP and/or COEP is indeed an issue, then the COOP and COEP headers must be set for OHIF. How to accomplish this varies per server or service that is hosting OHIF. The following are just a few examples.
|
||||
|
||||
:::tip
|
||||
In the default dev environment, the following can be set in the webpack.pwa.js file…
|
||||
|
||||
```javascript
|
||||
devServer: {
|
||||
headers: {
|
||||
"Cross-Origin-Opener-Policy": "same-origin",
|
||||
"Cross-Origin-Embedder-Policy": "require-corp"
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If deploying OHIF using Netlify, the Netlify configuration [file](https://docs.netlify.com/configure-builds/file-based-configuration/) can be used to configure the headers as such…
|
||||
|
||||
```
|
||||
[[headers]]
|
||||
# Define which paths this specific [[headers]] block will cover.
|
||||
for = "/*"
|
||||
|
||||
[headers.values]
|
||||
Cross-Origin-Opener-Policy = "same-origin"
|
||||
Cross-Origin-Embedder-Policy = "require-corp"
|
||||
```
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If OHIF is served behind nginx, then the headers can be set in the nginx.conf file as follows. The [template nginx configuration file](https://github.com/OHIF/Viewers/blob/master/.docker/Viewer-v3.x/default.conf.template) for creating a [OHIF Docker image](./docker.md#building-the-docker-image) has an example of this too.
|
||||
```nginx
|
||||
server {
|
||||
location / {
|
||||
add_header Cross-Origin-Opener-Policy same-origin;
|
||||
add_header Cross-Origin-Embedder-Policy require-corp;
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
## CORP - Cross-Origin Resource Policy
|
||||
|
||||
The CORP HTTP response header indicates which origins can read and use a resource. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy) for more information.
|
||||
|
||||
### Header Values (see [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy#usage) for more information)
|
||||
|
||||
|Value|Description|
|
||||
|-----|-----------|
|
||||
|same-site|Only requests from the same site can read the resource.|
|
||||
|same-origin|Only requests from the same origin can read the resource.|
|
||||
|cross-origin|Requests from any origin can read the resource. The value is useful and [exists](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy#relationship_to_cross-origin_embedder_policy_coep) primarily for letting documents with the [COEP require-corp value](#header-values-pertinent-to-ohif-see-mdn-for-more-information-1) know that the resource is ok to be embedded|
|
||||
|
||||
### OHIF and CORP
|
||||
|
||||
There are two scenarios where the CORP header is relevant to OHIF:
|
||||
|
||||
- [PDF from a Cross Origin DICOMweb Data Source](#pdf-from-a-cross-origin-dicomweb-data-source)
|
||||
- [OHIF as a Cross-origin Resource in an iframe](#ohif-as-a-cross-origin-resource-in-an-iframe)
|
||||
|
||||
Both these scenarios stem from the fact that OHIF has to be served with the [COEP](#coep---cross-origin-embedder-policy) header to support [SharedArrayBuffer](#sharedarraybuffer).
|
||||
|
||||
#### PDF from a Cross Origin DICOMweb Data Source
|
||||
|
||||
There are some DICOMweb data sources (e.g. dcm4chee) whereby OHIF uses the data source’s `/rendered` endpoint to embed a DICOM PDF document in the OHIF DOM using an `<object>` tag.
|
||||
|
||||
As specified for the [COEP require-corp value](#header-values-pertinent-to-ohif-see-mdn-for-more-information-1), a page like OHIF with COEP header `require-corp` can embed cross-origin resources in DOM elements that have the [`crossorigin` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin) OR the resource is delivered with an appropriate CORP header. The `<object>` tag does NOT support the `crossorigin` attribute. As such, the PDF must be delivered with a CORP header.
|
||||
|
||||
:::tip
|
||||
Setting the CORP header varies per server or service that is hosting the data source. The following is just one example.
|
||||
|
||||
For a dcm4chee DICOMweb data source composed in Docker behind nginx, the CORP header can be configured in the nginx.conf file as such:
|
||||
|
||||
```nginx
|
||||
add_header 'Cross-Origin-Resource-Policy' 'cross-origin' always;
|
||||
```
|
||||
|
||||
If the dcm4chee server and the OHIF server are hosted on the same site, then the following would also work:
|
||||
```nginx
|
||||
add_header 'Cross-Origin-Resource-Policy' 'same-site' always;
|
||||
```
|
||||
:::
|
||||
|
||||
#### OHIF as a Cross-origin Resource in an iframe
|
||||
|
||||
There are cases where [OHIF is embedded in an iframe](./iframe.md) and the embedding page is from a different origin. Again due to the [security requirements for SharedArrayBuffer](#security-requirements), [both OHIF and the embedding page](#iframe) must have the appropriate COEP header. In this scenario, OHIF is the cross-origin resource and since the `<iframe>` tag does not support the `crossorigin` attribute, OHIF must be served with the appropriate CORP header.
|
||||
|
||||
:::info
|
||||
Setting the CORP header such that OHIF can be embedded in an iframe varies per server or service hosting OHIF. What follows are just a few examples. Note that whenever the embedding page is hosted on the same site as OHIF, consider using the `same-site` value instead of `cross-origin`.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
In the default dev environment, the following can be set in the webpack.pwa.js file…
|
||||
|
||||
```javascript
|
||||
devServer: {
|
||||
headers: {
|
||||
"Cross-Origin-Resource-Policy": "cross-origin",
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If deploying OHIF using Netlify, the Netlify configuration [file](https://docs.netlify.com/configure-builds/file-based-configuration/) can be used to configure the header as such…
|
||||
|
||||
```
|
||||
[[headers]]
|
||||
# Define which paths this specific [[headers]] block will cover.
|
||||
for = "/*"
|
||||
|
||||
[headers.values]
|
||||
Cross-Origin-Resource-Policy = "cross-origin"
|
||||
```
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If OHIF is served behind nginx, then the header can be set in the nginx.conf file as follows.
|
||||
|
||||
```nginx
|
||||
server {
|
||||
location / {
|
||||
add_header Cross-Origin-Resource-Policy cross-origin;
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
@ -4,10 +4,14 @@ sidebar_position: 4
|
||||
|
||||
# Docker
|
||||
|
||||
The OHIF source code provides a Dockerfile to create and run a Docker image that containerizes an [nginx](https://www.nginx.com/) web server serving the OHIF Viewer.
|
||||
The OHIF source code provides a [Dockerfile](https://github.com/OHIF/Viewers/blob/master/Dockerfile) to create and run a Docker image that containerizes an [nginx](https://www.nginx.com/) web server serving the OHIF Viewer.
|
||||
|
||||
:::info
|
||||
This Dockerfile is the same used to generate the [OHIF image(s) on Docker Hub](https://hub.docker.com/r/ohif/app/tags).
|
||||
:::
|
||||
|
||||
|
||||
## Prequisites
|
||||
## Prerequisites
|
||||
The machine on which to build and run the Docker container must have:
|
||||
1. All of the [requirements](./build-for-production.md#build-for-production) for building a production version of OHIF.
|
||||
2. A checked out branch of the OHIF Viewer.
|
||||
@ -16,12 +20,16 @@ The machine on which to build and run the Docker container must have:
|
||||
## Building the Docker Image
|
||||
The docker image can be built from a terminal window as such:
|
||||
1. Switch to the OHIF Viewer code root directory.
|
||||
2. Issue the following docker command. Note that what follows `-t` flag is the `{name}:{tag}` for the Docker image and is arbitrary when creating a local Docker image.
|
||||
2. Issue the following Docker command. Note that what follows `-t` flag is the `{name}:{tag}` for the Docker image and is arbitrary when creating a local Docker image.
|
||||
|
||||
```sh
|
||||
docker build . -t ohif-viewer-image
|
||||
```
|
||||
|
||||
:::tip
|
||||
Building a Docker image comes in handy when OHIF has been customized (e.g. with custom extensions, modes, hanging protocols, etc.). For convenience, there are basic OHIF images built in Docker Hub. Find the latest [release](https://hub.docker.com/r/ohif/app/tags?page=1&name=latest) and [dev](https://hub.docker.com/r/ohif/app/tags?page=1&name=beta) images all in Docker Hub.
|
||||
:::
|
||||
|
||||
## Running the Docker Container
|
||||
Once the Docker image has been built, it can be run as a container from the command line as in the block below. Note that the last argument to the command is the name of the Docker image and the table below describes the other arguments.
|
||||
|
||||
@ -36,18 +44,208 @@ Once the Docker image has been built, it can be run as a container from the comm
|
||||
docker run -d -p 3000:80/tcp --name ohif-viewer-container ohif-viewer-image
|
||||
```
|
||||
|
||||
:::tip
|
||||
Any of the [Docker Hub images](https://hub.docker.com/r/ohif/app/tags) can be easily run as a Docker container.
|
||||
|
||||
The following is the command to run the Docker container using the latest released OHIF Docker Hub image.
|
||||
|
||||
```sh
|
||||
docker run -d -p 3000:80/tcp --name LatestReleasedOHIF ohif/app:latest
|
||||
```
|
||||
|
||||
Simply replace `latest` at the end of the command with any of the tags for a specific version.
|
||||
:::
|
||||
|
||||
### Configuring the `nginx` Listen Port
|
||||
|
||||
The Dockerfile and entry point use the `${PORT}` environment variable as the port that the `nginx` server uses to serve the web server. The default value for `${PORT}` is `80`. One way to set this environment variable is to use the `-e` switch when running the container with `docker run`. The block below gives an example where the listen port is set to `8080` and publised on the host as `3000`.
|
||||
The Dockerfile and entry point use the `${PORT}` environment variable as the port that the `nginx` server uses to serve the web server. The default value for `${PORT}` is `80`. One way to set this environment variable is to use the `-e` switch when running the container with `docker run`. The block below gives an example where the listen port is set to `8080` and published on the host as `3000`.
|
||||
|
||||
```sh
|
||||
docker run -d -e PORT=8080 -p 3000:8080/tcp --name ohif-viewer-container ohif-viewer-image
|
||||
```
|
||||
|
||||
### Configuring the OHIF config file
|
||||
### Specifying the OHIF config File
|
||||
|
||||
The OHIF [config file](../configuration/configurationFiles.md) to use can be specified by mounting it as a volume for the Docker container using the `-v` flag. If the OHIF config file is on the local file system then it can be specified as below. Note that depending on the version of Docker, an absolute path to the config file might be required.
|
||||
There are two approaches for specifying the OHIF configuration file for a Docker container:
|
||||
|
||||
- [Volume Mounting](#volume-mounting)
|
||||
- [Environment Variable](#environment-variable)
|
||||
|
||||
#### Volume Mounting
|
||||
|
||||
The OHIF [config file](../configuration/configurationFiles.md) can be specified by mounting it as a volume for the Docker container using the `-v` flag. If the OHIF config file is on the local file system then it can be specified as below.
|
||||
|
||||
```sh
|
||||
docker run -d -p 3000:80/tcp -v /path/to/config/file.js:/usr/share/nginx/html/app-config.js --name ohif-viewer-container ohif-viewer-image
|
||||
```
|
||||
:::tip
|
||||
Depending on the version of Docker, an absolute path to the local source config file might be required.
|
||||
:::
|
||||
#### Environment Variable
|
||||
|
||||
In certain scenarios, such as deploying the Docker container to Google Cloud, it might be convenient to specify the configuration file (contents) as an environment variable. That environment variable is `${APP_CONFIG}` and it can be set in the `docker run` command using the `-e` switch.
|
||||
|
||||
:::tip
|
||||
It is important to stress here that the environment variable is the contents of the configuration file and NOT the path to the config file as is [typically specified](https://docs.ohif.org/configuration/configurationFiles#configuration-files) for development and build environments or for the [volume mounting method](#volume-mounting).
|
||||
:::
|
||||
|
||||
Below the `cat` command is used to convert the configuration file to a string and its result set as the `${APP_CONFIG}` environment variable.
|
||||
|
||||
```sh
|
||||
docker run -d -p 3000:80/tcp -e APP_CONFIG="$(cat /path/to/the/config/file)" --name ohif-viewer-container ohif-viewer-image
|
||||
```
|
||||
|
||||
:::tip
|
||||
To be safe, remove single line comments (i.e. `//`) from the configuration file because the presence of these comments might cause the configuration file to be prematurely truncated when it is served to the OHIF client.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
As an alternative to the `cat` command, convert the configuration file to a single line and copy and paste it as the value to the `${APP_CONFIG}` environment variable on the `docker run` line. Editors such as [Visual Studio Code](https://stackoverflow.com/questions/46491061/shortcut-for-joining-two-lines) and [Notepad++](https://superuser.com/questions/518229/how-do-i-remove-linebreaks-in-notepad) have 'Join Lines' commands to facilitate this.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If both the [volume mounting method](#volume-mounting) and the [environment variable method](#environment-variable) are used, the volume mounting method will take precedence.
|
||||
:::
|
||||
|
||||
### Embedding in an iframe
|
||||
|
||||
If the OHIF instance served by the Docker image is to be embedded in an `iframe`, and if [cross-origin isolation](./cors.md#cross-origin-isolation) is required, then the [Cross Origin Resource Policy (CORP) header value](https://github.com/OHIF/Viewers/blob/8a8ae237d26faf123abeb073cbf0cd426c3e9ef2/.docker/Viewer-v3.x/default.conf.template#L10) that OHIF is served with will have to be updated accordingly. More information on CORP and `iframe`s can be found [here](./cors.md#ohif-as-a-cross-origin-resource-in-an-iframe).
|
||||
|
||||
:::tip
|
||||
For SSL Docker deployments, the CORP header value is set [here](https://github.com/OHIF/Viewers/blob/8a8ae237d26faf123abeb073cbf0cd426c3e9ef2/.docker/Viewer-v3.x/default.ssl.conf.template#L12).
|
||||
:::
|
||||
|
||||
## SSL
|
||||
|
||||
:::caution
|
||||
We make no claims or guarantees regarding this section concerning security. If in doubt, enlist the help of an expert and conduct proper audits.
|
||||
:::
|
||||
|
||||
### Why SSL?
|
||||
As described [here](./cors.md), OHIF must be used in a [secure context](./cors.md#secure-context) in order to fully leverage all of OHIF's capabilities. Whenever OHIF is not running in a secure context and is navigated to using the OHIF's server IP address (e.g. `http://192.168.1.162:3000`) or domain name (e.g. `http://my.ohif.server`) then the following popup message will be displayed in OHIF
|
||||
|
||||

|
||||
|
||||
and the following message will appear in the browser console.
|
||||
|
||||

|
||||
|
||||
:::info
|
||||
The above indicate that OHIF is not running in a secure context. Among other things, this means information transferred to/from OHIF is not encrypted and certain capabilities such as 3D volume loading will NOT work. However, basic stack viewport functionality will continue to function.
|
||||
|
||||
Consideration must be given as to whether OHIF should be deployed in a secure context over SSL.
|
||||
:::
|
||||
|
||||
### Specifying the SSL Port, Certificate and Private Key
|
||||
|
||||
For convenience, the [built Docker image](#building-the-docker-image) can be run over SSL by
|
||||
- setting the `${SSL_PORT}` environment variable
|
||||
- volume mounting the SSL certificate
|
||||
- volume mounting the SSL private key
|
||||
|
||||
:::info
|
||||
The volume mounted SSL certificate and private key are mapped to the [`ssl_certificate`](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate) and [`ssl_certificate_key`](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_key) `nginx` directives respectively.
|
||||
:::
|
||||
|
||||
Similar to the [`nginx` listen port](#configuring-the-nginx-listen-port), the `${SSL_PORT}` environment variable is the internal port that `nginx` listens on to serve the OHIF web server over SSL and has to be likewise published via the `-p` switch.
|
||||
|
||||
The following is an example command running the Docker container over SSL. Note that depending on the version of Docker, an absolute path to the certificate and private key files might be required.
|
||||
|
||||
```sh
|
||||
docker run -d -e SSL_PORT=443 -p 3003:443/tcp -v /path/to/certificate:/etc/ssl/certs/ssl-certificate.crt -v /path/to/private/key:/etc/ssl/private/ssl-private-key.key --name ohif-viewer-container ohif-viewer-image
|
||||
```
|
||||
|
||||
:::caution
|
||||
The above deploys OHIF over SSL using `nginx`'s default SSL configuration. For further OHIF server hardening and security configuration, consider enlisting an expert and then editing OHIF's `nginx` [SSL template configuration file](https://github.com/OHIF/Viewers/blob/8a8ae237d26faf123abeb073cbf0cd426c3e9ef2/.docker/Viewer-v3.x/default.ssl.conf.template) with further [security settings](https://nginx.org/en/docs/http/ngx_http_ssl_module.html) and [tweaks](http://nginx.org/en/docs/http/configuring_https_servers.html) and then [build a new Docker image](#building-the-docker-image) from there.
|
||||
:::
|
||||
|
||||
:::caution
|
||||
The private key is a secure entity and should have restricted access. Keep it safe!
|
||||
:::
|
||||
|
||||
:::caution
|
||||
The presence of the `${SSL_PORT}` environment variable is used to trigger to deploy over SSL as opposed to HTTP. If `${SSL_PORT}` is NOT defined, then HTTP is used even if the certificate and private key volumes are mounted.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
The read and write permissions of the source, mounted volumes are preserved in the Docker container. The volume mounted certificate and private key require read permission.
|
||||
|
||||
One way to ensure both are readable is to issue the following on the host system terminal prior to running the Docker container and mounting the certificate and private key volumes.
|
||||
|
||||
```sh
|
||||
sudo chmod 644 /path/to/certificate /path/to/private/key
|
||||
```
|
||||
:::
|
||||
|
||||
:::tip
|
||||
The SSL certificate and private key can be either [CA issued](#ca-signed-certificates) or [self-signed](#self-signed-certificates).
|
||||
:::
|
||||
|
||||
|
||||
### CA Signed Certificates
|
||||
|
||||
According to [SSL.com](https://www.ssl.com/faqs/what-is-a-certificate-authority/), a global certificate authority (CA) is a trusted authority and organization that guarantees the identity of other, third-party entities and guarantees the integrity of the electronic information (e.g. web site data) those third-party entities provide and deliver.
|
||||
|
||||
There are many globally trusted CAs. Below is a non-exhaustive list of some CAs including links to some documentation for creating and installing certificates and keys from those authorities to be used with `nginx`.
|
||||
- [GoDaddy](https://ca.godaddy.com/help/nginx-install-a-certificate-6722)
|
||||
- [Let's Encrypt](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/)
|
||||
- [digicert](https://www.digicert.com/kb/csr-ssl-installation/nginx-openssl.htm)
|
||||
|
||||
|
||||
### Self-Signed Certificates
|
||||
|
||||
According to [Entrust](https://www.entrust.com/resources/faq/what-is-a-self-signed-certificate), a self-signed certificate is one that is NOT signed by a trusted, public [CA authority](#ca-signed-certificates), but instead (typically) signed by the developer or individual or organization responsible for a web site.
|
||||
|
||||
Browsers will treat self-signed certificates as not secure because the signer is not publicly recognized and trusted. When visiting a site encrypted with a self-signed certificate, the browser will present a screen similar to the following warning about the potential risk.
|
||||
|
||||

|
||||
|
||||
For a self-signed certificate this is normal and expected. Clicking the `Advanced` button displays further information as well as a link for proceeding to site that the certificate is encrypting.
|
||||
|
||||

|
||||
|
||||
|
||||
Self-signed certificates might be appropriate for testing or perhaps deploying a site within an organization's internal LAN. In any case, consult an expert prior to deploying OHIF over SSL.
|
||||
|
||||
:::tip
|
||||
A self-signed certificate can be generated using [`openssl`](https://www.openssl.org/) on the command line.
|
||||
:::
|
||||
|
||||
To create a self-signed certificate:
|
||||
1. Open a command prompt.
|
||||
2. Issue the following command:
|
||||
```sh
|
||||
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /desired/key/directory/self-signed-private.key -out /desired/cert/directory/self-signed.crt
|
||||
```
|
||||
|
||||
The chart below describes each of the items in the command.
|
||||
|
||||
|Command Item|Description|
|
||||
|------------|-----------|
|
||||
|sudo|temporarily grant access as the root/super user to run the `openssl` command|
|
||||
|openssl|the command line tool for creating and managing certificates and keys|
|
||||
|req|this together with the subsequent `-x509` indicates to request to generate a self-signed certificate|
|
||||
|-x509|this together with the `req` indicates to request to generate a self-signed certificate|
|
||||
|-nodes|skip the option to secure the certificate with a passphrase; this allows `nginx` to start up with without intervention to enter a passphrase each time|
|
||||
|-days 365|the number of days the certificate will be valid for|
|
||||
|-newkey rsa:2048|create the a new certificate and key together and make an RSA key that is 2048 bits long|
|
||||
|-keyout|the path and file name where the private key will be written to|
|
||||
|-out|the path and file name where the certificate will be written to|
|
||||
|
||||
3. Answer the prompts that follow. The table below lists the various prompts. The default value for each prompt is shown within the square brackets. The most important prompt is `Common Name (e.g. server FQDN or YOUR name)`. For this enter the IP address of the OHIF server being secured.
|
||||
|
||||
|Prompt|
|
||||
|------|
|
||||
|Country Name (2 letter code) [AU]|
|
||||
|State or Province Name (full name) [Some-State]|
|
||||
|Locality Name (eg, city) []|
|
||||
|Organization Name (eg, company) [Internet Widgits Pty Ltd]|
|
||||
|Organizational Unit Name (eg, section) []|
|
||||
|Common Name (e.g. server FQDN or YOUR name) []|
|
||||
|Email Address []|
|
||||
|
||||
4. Once completed, the self-signed certificate and private key will be in the locations specified by the `-keyout` and `-out` flags and can be [volume mounted](#specifying-the-ssl-port-certificate-and-private-key) accordingly to the OHIF Docker container.
|
||||
|
||||
:::tip
|
||||
Windows' users can access `openssl` using [Windows Subsystem for Linux (WSL)](https://learn.microsoft.com/en-us/windows/wsl/).
|
||||
:::
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
sidebar_position: 8
|
||||
---
|
||||
|
||||
# Nginx + Image Archive
|
||||
|
||||
Loading…
Reference in New Issue
Block a user