Configuring CAST Imaging for Docker/Podman with a reverse proxy and a context URL

Configure CAST Imaging on Docker or Podman behind an NGINX reverse proxy using a context URL

Overview

This documentation provides information about placing your CAST Imaging installation behind a reverse proxy, i.e. for load balancing, caching, or security, and specifically using a context URL such as http://<fqdn>/some-path. CAST recommends the use of an NGINX web server external link to provide the reverse proxy.

Assumptions

This documentation assumes that:

  • you are using a context URL such as http://<fqdn>/some-path and not the root http://<fqdn>/.
  • you are using either HTTPS to access NGINX, i.e. incoming requests will be accepted on TCP port 443, or a non-encrypted connection on TCP port 80.

Requirements

  • CAST Imaging v3 must be installed and up and running before you proceed.
  • If you intend to use HTTPS to access NGINX, you should follow the instructions for generating the public/private key pair and configuring HTTPS on NGINX in HTTPS configuration for Linux via Docker and then return here.
  • NGINX can be installed on a dedicated machine or on an existing machine where CAST Imaging Docker containers are already running.
  • Some minor changes are required to CAST Imaging Docker containers, detailed in the instructions below.
  • Commands detailed below require execution with a user in the sudoers list.

Step 1 - Install NGINX

Install NGINX: this is beyond the scope of this document, instead please consult the following third-party documentation: https://nginx.org/en/docs/install.html external link.

Step 2 - Configure NGINX

When NGINX is installed, you now need to configure it. There are two parts to this process:

  • create the vHost configuration file
  • configure the reverse proxy

Step 2a - Create vHost configuration file

Out of the box, NGINX contains one “vHost” called “default”, serving various default files on port 80. CAST recommends creating a new vHost and using this specifically for the reverse proxy requirements. To add a new vHost, create a new empty .conf file using an editor such as vi or nano in the following location on disk (in our example the file is named with the machine’s FQDN imaging.corp.domain.com):

/etc/nginx/conf.d/imaging.corp.domain.com.conf

Step 2b - Configure the reverse proxy

The next step involves configuring NGINX to function in reverse proxy mode, i.e. to accept incoming connections and forward them to the relevant CAST Imaging services.

Edit the vHost configuration file (the same one you created in the previous step), add the following parameters and then save the file:

server { # simple reverse proxy
    listen 80;
    server_name imaging.corp.domain.com;
    server_tokens off;
    location /some-path {
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_cache off;
        proxy_cookie_flags ~.* secure samesite=None; # Required in ≥ 3.4.0-funcrel only
        proxy_pass http://imagingv3_VM.corp.domain.com:8090/;
        proxy_redirect off;
        proxy_set_header Connection '';
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        chunked_transfer_encoding off;
        client_max_body_size 100M;
    }
}

Where:

  • listen - indicates that we want NGINX to listen on all ipv4 addresses on the server, on port 80
  • server_name - indicates the FQDN on which NGINX will listen for incoming connections
  • server_tokens off - disables emitting NGINX version numbers on error pages and in the “Server” response header field.
  • location - sets the configuration depending on a request URI. The example above uses a context, i.e. /some-path
  • proxy_http_version - sets the HTTP protocol version for proxying, use 1.1
  • proxy_buffering - enables or disables buffering of responses from the proxied server - set to off
  • proxy_cache - defines a shared memory zone used for caching. - set to off
  • proxy_cookie_flags - required in ≥ 3.4.0-funcrel only: sets specific secure flags for cookies - see https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_flags external link for more information
  • proxy_pass - sets the protocol and address/port of the proxied server - set this to the machine on which the CAST Imaging v3 imaging-services component is installed, using port 8090 (unless you have customized it). The address can be specified as a domain name or IP address
  • proxy_set_header - allows redefining or appending fields to the request header passed to the proxied server - see https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header external link for more information
  • chunked_transfer_encoding - allows disabling chunked transfer encoding in HTTP/1.1 - set to off
  • client_max_body_size - sets the maximum allowed size of the client request body. This limit determines the maximum file size that will be accepted: if your users upload ZIP archive files during the application onboarding, set this to an appropriate limit to accept the file

Step 3 - Update imaging-services component

To ensure that the imaging-services component functions correctly behind the NGINX reverse proxy, you need to add some entries to the following files:

/opt/cast/installation/imaging-services/docker-compose.override.yml
/opt/cast/installation/imaging-services/.env
/opt/cast/installation/imaging-viewer/.env

.env files will be located on disk following a successful installation, whereas docker-compose.override.yml is not created during the installation - you will therefore need to create it if it does not already exist (see also Managing docker-compose.yml files).

Step 3a - Update docker-compose.override.yml

Add the following lines to the root services: block and then save the file:

services:
    sso-service:
        environment:
            KC_HOSTNAME_ADMIN_URL: ${PUBLIC_URL}/auth
            KC_HOSTNAME_STRICT_HTTPS: 'false'
            KC_HOSTNAME_URL: ${PUBLIC_URL}/auth
            KC_PROXY: 'edge'
            KC_PROXY_HEADERS: 'xforwarded'
            PROXY_ADDRESS_FORWARDING: 'true'
            PUBLIC_URL: ${PUBLIC_URL}
    gateway:
        environment:
            APP_CONTEXT: ${APP_CONTEXT}
    control-panel:
        environment:
            PUBLIC_URL: ${PUBLIC_URL}/
    auth-service:
        environment:
            NGINX_HOST: ${PUBLIC_URL}
            APP_CONTEXT: ${APP_CONTEXT}

Then set permissions on the docker-compose.override.yml file to ensure that “everyone” can read and execute it, and that the owner can also write to it:

$ chmod 755 docker-compose.override.yml

Step 3b - Update imaging-services/.env

Add the following lines to the end of the file and then save it:

APP_CONTEXT=/some-path
PUBLIC_URL=http://imaging.corp.domain.com/some-path

Where:

  • APP_CONTEXT - is the context URL you defined for location in the server block of the NGINX vHost you created earlier
  • PUBLIC_URL - is the full URL used to access CAST Imaging through NGINX: the protocol (http:// or https://), the FQDN defined for the parameter server_name and the context URL defined for location in the server block of the NGINX vHost you created earlier. The protocol is mandatory

Step 3c - Update imaging-viewer/.env

Add the following lines to the end of the file and then save it:

APP_CONTEXT=/some-path

Where:

  • APP_CONTEXT - is the context URL you defined for location in the server block of the NGINX vHost you created earlier

Step 4 - Update control_panel and keycloak schema

The control_panel and keycloak persistence schemas will be located on the PostgreSQL instance installed automatically as part of CAST Imaging, on the same machine as the imaging-services component. Run the following queries to update each to ensure that they function correctly with a reverse proxy in place.

You can run the queries with any PostgreSQL client, such as pgAdmin or DBeaver. If no client is available, run them with psql inside the PostgreSQL container. From /opt/cast/installation/imaging-services/, open a shell in the container and start psql:

$ docker compose exec -it postgres bash
$ psql -U postgres

Run the queries in the psql prompt, then enter \q to quit psql and exit to leave the container.

Step 4a - Update control_panel schema

Update the keycloak.uri property in the properties table (control_panel schema) in the postgres database with the PUBLIC_URL:

update control_panel.properties p set value = 'http://imaging.corp.domain.com/some-path' where p.prop_key='keycloak.uri';

Step 4b - Update keycloak schema

Update the frontendUrl property in the realm_attribute table in the keycloak schema with the PUBLIC_URL:

delete from keycloak.realm_attribute ra where ra.realm_id in (select r.id from keycloak.realm r where r.name in ('aip-realm', 'master')) and ra.name = 'frontendUrl';

insert into keycloak.realm_attribute values ('frontendUrl', (select r.id from keycloak.realm r where r.name='aip-realm'), 'http://imaging.corp.domain.com/some-path/auth/');

insert into keycloak.realm_attribute values ('frontendUrl', (select r.id from keycloak.realm r where r.name='master'),'http://imaging.corp.domain.com/some-path/auth/');

Step 5 - Restart services

To ensure the changes you have made are taken into account, you should restart the imaging-services and imaging-viewer components and NGINX:

imaging-services and imaging-viewer components

Issue the following command from both of the following locations:

  • /opt/cast/installation/imaging-services/
  • /opt/cast/installation/imaging-viewer/
# docker compose down
# docker compose up -d

This command will rebuild only the images/containers with the changes you have implemented.

NGINX

Restart NGINX using the preferred method for your installation.

Step 6 - Check access

Check that you can access CAST Imaging from the FQDN and context URL you declared in the NGINX vHost, e.g. http://imaging.corp.domain.com/some-path.

Troubleshooting

The browser redirects to HTTPS when NGINX listens on HTTP

If the login page loads over http:// but the browser switches to https:// after you sign in and fails with ERR_SSL_PROTOCOL_ERROR, the browser is enforcing HTTP Strict Transport Security (HSTS) for your domain. This happens when the domain, or a parent domain with subdomains included, is on the browser’s built-in HSTS preload list or has previously sent an HSTS header. The browser then upgrades every request to HTTPS before it is sent, and this cannot be overridden in the browser. CAST Imaging is not at fault.

To confirm, open chrome://net-internals/#hsts (Chrome) or edge://net-internals/#hsts (Edge) and query your domain. A static_sts_domain or dynamic_sts_domain entry means HSTS applies.

To resolve it, do one of the following:

  • Configure HTTPS on NGINX (see HTTPS configuration for Linux via Docker) and use an https:// URL in PUBLIC_URL and in the Step 4 queries.
  • Use a hostname that is not covered by HSTS in server_name, PUBLIC_URL and the Step 4 queries.

After changing PUBLIC_URL, recreate the containers with docker compose up -d from /opt/cast/installation/imaging-services/ - a plain docker restart keeps the old value.