Connect OHIF to Orthanc using Docker containers on Synology nas

Hi,
I need to connect OHIF Viewer to Orthanc.
As a physical server I use a Synology nas with the DSM 7.1 operating system version.

I currently use Orthanc and OHIF as docker containers.

Orthanc: Version: mainline (20220510T030919)
name jodogne/orthanc-plugins/

OHIF: Version 4.12.35
name ohif/viewer/

Synology’s ip address is 192.168.2.167
The ports of the containers installed on the Synology nas are mapped as follows:
Orthanc container - Synology
4242 > 49178
8042 > 49179

OHIF container - Synology
443 > 49182
80 > 49183

Both applications called individually work correctly.
If I try to connect OHIF to Orthanc, using the port 49183
I don’t see the my Orthanc series but those of the OHIF demo website.

I have read many posts on the subject, and I think I understand that my problem is with the configuration of nginx. Unfortunately I don’t know it and I can’t figure out how to configure it.
Can anyone help me ?
A thousand thanks ….

Daniele.

These are the configuration files I use:

*****************************************************************************************
Orthanc, orthanc.json
*****************************************************************************************

{
  /**
   * General configuration of Orthanc
   **/
  
  "Name" : "Orthanc inside Docker",
  "StorageDirectory" : "/var/lib/orthanc/db",
  "IndexDirectory" : "/var/lib/orthanc/db",
  "StorageCompression" : false,
  "MaximumStorageSize" : 0,
  "MaximumPatientCount" : 0,
  "MaximumStorageCacheSize" : 128,
  "LuaScripts" : [
  ],
  "Plugins" : [ 
    "/usr/share/orthanc/plugins", "/usr/local/share/orthanc/plugins"
  ],

  "ConcurrentJobs" : 2,

  "DicomWeb" : {
    "Enable": true,
    "Root": "/dicom-web/",
    "EnableWado": true,
    "WadoRoot": "/wado",
    "Host": "127.0.0.1",
    "Ssl": false,
    "StowMaxInstances": 10,
    "StowMaxSize": 10,
    "Servers" : {
      "TEST" : [ "http://127.0.0.1:8042/dicom-web/","daniele","prova" ]
    }   
  },

  /**
   * Configuration of the HTTP server
   **/
  "HttpServerEnabled" : true,
  "OrthancExplorerEnabled" : true,

  "HttpPort" : 8042,

  "HttpDescribeErrors" : true,
  "HttpCompressionEnabled" : true,
  "WebDavEnabled" : true,
  "WebDavDeleteAllowed" : false,
  "WebDavUploadAllowed" : true,

  /**
   * Configuration of the DICOM server
   **/

  "DicomServerEnabled" : true,
  "DicomAet" : "ORTHANC",
  "DicomCheckCalledAet" : false,

  // The DICOM port
  "DicomPort" : 4242,

  "DefaultEncoding" : "Latin1",
  "AcceptedTransferSyntaxes" : [ "1.2.840.10008.1.*" ],

  /**
     "DeflatedTransferSyntaxAccepted"     : true,
     "JpegTransferSyntaxAccepted"         : true,
     "Jpeg2000TransferSyntaxAccepted"     : true,
     "JpegLosslessTransferSyntaxAccepted" : true,
     "JpipTransferSyntaxAccepted"         : true,
     "Mpeg2TransferSyntaxAccepted"        : true,
     "RleTransferSyntaxAccepted"          : true,
     "Mpeg4TransferSyntaxAccepted"        : true,  // New in Orthanc 1.6.0
     "H265TransferSyntaxAccepted"         : true,  // New in Orthanc 1.9.0
  **/
    
  "UnknownSopClassAccepted" : false,
  "DicomScpTimeout" : 30,

  /**
   * Security-related options for the HTTP server
   **/

  "RemoteAccessAllowed" : true,
  "SslEnabled" : false,
  "SslCertificate" : "certificate.pem",
  "SslMinimumProtocolVersion" : 4,

  /**
    "SslCiphersAccepted" : [ "AES128-GCM-SHA256" ],
  **/

  "SslVerifyPeers" : false,
  "SslTrustedClientCertificates" : "trustedClientCertificates.pem",
 
  /**
     "AuthenticationEnabled" : true,
   **/

  "RegisteredUsers" : {
    // "alice" : "alicePassword"
    "amministratore" : "123123123",
    "daniele" : "prova"
  },

  "Worklists" : {
	"Enable": true,
	"Database": "/var/lib/orthanc/WorklistsDatabase"  // Path to the folder with the worklist files
  },

  /**
   * Security-related options for the DICOM connections (SCU/SCP)
   **/

  "DicomTlsEnabled" : false,
  /**
     "DicomTlsPrivateKey" : "orthanc.key",
  **/

  "DicomTlsRemoteCertificateRequired" : true,
  "DicomAlwaysAllowEcho" : true,
  "DicomAlwaysAllowStore" : true,
  "DicomAlwaysAllowFind" : false,
  "DicomAlwaysAllowFindWorklist" : false,
  "DicomAlwaysAllowGet" : false,
  "DicomAlwaysAllowMove" : false,
  "DicomCheckModalityHost" : false,

  /**
   * Network topology
   **/

  // The list of the known DICOM modalities. This option is ignored if
  // "DicomModalitiesInDatabase" is set to "true", in which case you
  // must use the REST API to define modalities.
  "DicomModalities" : {
    /**
     * Uncommenting the following line would enable Orthanc to
     * connect to an instance of the "storescp" open-source DICOM
     * store (shipped in the DCMTK distribution), as started by the
     * command line "storescp 2000". The first parameter is the
     * AET of the remote modality (cannot be longer than 16 
     * characters), the second one is the remote network address,
     * and the third one is the TCP port number corresponding
     * to the DICOM protocol on the remote modality (usually 104).
     **/
    // "sample" : [ "STORESCP", "127.0.0.1", 2000 ]
	"MYLABX8" : [ "MYLABX8", "172.31.255.4", 11112 ],
	"MYLAB8" : [ "MYLAB8", "172.31.255.1", 6104 ],
	"Test1" : [ "FINDSCU", "172.31.255.59", 6104 ]
	
    /**
     * A fourth parameter is available to enable patches for
     * specific PACS manufacturers. The allowed values are currently:
     * - "Generic" (default value),
     * - "GenericNoWildcardInDates" (to replace "*" by "" in date fields 
     *   in outgoing C-FIND requests originating from Orthanc),
     * - "GenericNoUniversalWildcard" (to replace "*" by "" in all fields
     *   in outgoing C-FIND SCU requests originating from Orthanc),
     * - "Vitrea",
     * - "GE" (Enterprise Archive, MRI consoles and Advantage Workstation
     *   from GE Healthcare).
     *
     * This parameter is case-sensitive.
     **/
    // "vitrea" : [ "VITREA", "192.168.1.1", 104, "Vitrea" ]
  },
 
  "DicomModalitiesInDatabase" : false,
  "DicomEchoChecksFind" : false,
  "DicomScuTimeout" : 10,
  "DicomScuPreferredTransferSyntax" : "1.2.840.10008.1.2.1",
  "DicomThreadsCount" : 4,

  // The list of the known Orthanc peers. This option is ignored if
  // "OrthancPeersInDatabase" is set to "true", in which case you must
  // use the REST API to define Orthanc peers.
  "OrthancPeers" : {
    /**
     * Each line gives the base URL of an Orthanc peer, possibly
     * followed by the username/password pair (if the password
     * protection
 is enabled on the peer).
     **/
    // "peer"  : [ "http://127.0.0.1:8043/", "alice", "alicePassword" ]
    // "peer2" : [ "http://127.0.0.1:8044/" ]

    /**
     * This is another, more advanced format to define Orthanc
     * peers. It notably allows one to specify HTTP headers, a HTTPS
     * client certificate in the PEM format (as in the "--cert" option
     * of curl), or to enable PKCS#11 authentication for smart cards.
     *
     * The "Timeout" option allows one to overwrite the global value
     * "HttpTimeout" on a per-peer basis.
     **/
    // "peer" : {
    //   "Url" : "http://127.0.0.1:8043/",
    //   "Username" : "alice",
    //   "Password" : "alicePassword",
    //   "HttpHeaders" : { "Token" : "Hello world" },
    //   "CertificateFile" : "client.crt",
    //   "CertificateKeyFile" : "client.key",
    //   "CertificateKeyPassword" : "certpass",
    //   "Pkcs11" : false,
    //   "Timeout" : 42            // New in Orthanc 1.9.1
    // }
  },
 
  "OrthancPeersInDatabase" : false,
  "HttpProxy" : "",
  "HttpVerbose" : false,
  "HttpTimeout" : 60,
  "HttpsVerifyPeers" : true,
  "HttpsCACertificates" : "/etc/ssl/certs/ca-certificates.crt",

  // Maximum number of storage commitment reports (i.e. received from
  // remote modalities) to be kept in memory (new in Orthanc 1.6.0).
  "StorageCommitmentReportsSize" : 100,

  "TranscodeDicomProtocol" : true,
  "BuiltinDecoderTranscoderOrder" : "After",
  "IngestTranscodingOfUncompressed" : true,
  "IngestTranscodingOfCompressed" : true,
  "DicomLossyTranscodingQuality" : 90,
  "SyncStorageArea" : true,
  "MallocArenaMax" : 5,
  "DeidentifyLogs" : true,
  "DeidentifyLogsDicomVersion" : "2021b",
  "MaximumPduLength" : 16384,
  "CheckRevisions" : false,
  "SynchronousZipStream" : true,
  "ZipLoaderThreads": 0,

  "ExtraMainDicomTags" : {
    "Instance" : [
      "Rows",
      "Columns",
      "ImageType",
      "SOPClassUID",
      "ContentDate",
      "ContentTime",
      "FrameOfReferenceUID",
      "PixelSpacing",
      "SpecificCharacterSet",
      "BitsAllocated"
    ],
    "Series" : [],
    "Study": [],
    "Patient": []
  },
  
 Orthanc 1.11.0)
  "Warnings" : {
    "W001_TagsBeingReadFromStorage": true,
    "W002_InconsistentDicomTagsInDb": true
  }
}
*****************************************************************************************
*****************************************************************************************
OHIF - app-config.js
*****************************************************************************************
window.config = {
  // default: '/'
  routerBasename: '/',
  extensions: [],
  showStudyList: true,
  filterQueryParam: false,
  disableServersCache: false,
  studyPrefetcher: {
    enabled: true,
    order: 'closest',
    displaySetCount: 3,
    preventCache: false,
    prefetchDisplaySetsTimeout: 300,
    maxNumPrefetchRequests: 100,
    displayProgress: true,
    includeActiveDisplaySet: true,
  },
  servers: {
    dicomWeb: [
      {
        name: 'Orthanc',
        wadoUriRoot: 'http://192.168.2.167:49179/wado',
        qidoRoot: 'http://192.168.2.167:49179/dicom-web',
        wadoRoot: 'http://192.168.2.167:49179/dicom-web',
        qidoSupportsIncludeField: true,
        imageRendering: 'wadors',
        thumbnailRendering: 'wadors',
        enableStudyLazyLoad: true,
        supportsFuzzyMatching: true,
       },
    ],
  },

  // Extensions should be able to suggest default values for these?
  // Or we can require that these be explicitly set
  hotkeys: [
    // ~ Global
    {
      commandName: 'incrementActiveViewport',
      label: 'Next Viewport',
      keys: ['right'],
    },
    {
      commandName: 'decrementActiveViewport',
      label: 'Previous Viewport',
      keys: ['left'],
    },
    // Supported Keys: https://craig.is/killing/mice
    // ~ Cornerstone Extension
    { commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] },
    { commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] },
    { commandName: 'invertViewport', label: 'Invert', keys: ['i'] },
    {
      commandName: 'flipViewportVertical',
      label: 'Flip Horizontally',
      keys: ['h'],
    },
    {
      commandName: 'flipViewportHorizontal',
      label: 'Flip Vertically',
      keys: ['v'],
    },
    { commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] },
    { commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] },
    { commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] },
    { commandName: 'resetViewport', label: 'Reset', keys: ['space'] },
    // clearAnnotations
    { commandName: 'nextImage', label: 'Next Image', keys: ['down'] },
    { commandName: 'previousImage', label: 'Previous Image', keys: ['up'] },
    // firstImage
    // lastImage
    {
      commandName: 'previousViewportDisplaySet',
      label: 'Previous Series',
      keys: ['pagedown'],
    },
    {
      commandName: 'nextViewportDisplaySet',
      label: 'Next Series',
      keys: ['pageup'],
    },
    // ~ Cornerstone Tools
    { commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
    // ~ Window level presets
    {
      commandName: 'windowLevelPreset1',
      label: 'W/L Preset 1',
      keys: ['1'],
    },
    {
      commandName: 'windowLevelPreset2',
      label: 'W/L Preset 2',
      keys: ['2'],
    },
    {
      commandName: 'windowLevelPreset3',
      label: 'W/L Preset 3',
      keys: ['3'],
    },
    {
      commandName: 'windowLevelPreset4',
      label: 'W/L Preset 4',
      keys: ['4'],
    },
    {
      commandName: 'windowLevelPreset5',
      label: 'W/L Preset 5',
      keys: ['5'],
    },
    {
      commandName: 'windowLevelPreset6',
      label: 'W/L Preset 6',
      keys: ['6'],
    },
    {
      commandName: 'windowLevelPreset7',
      label: 'W/L Preset 7',
      keys: ['7'],
    },
    {
      commandName: 'windowLevelPreset8',
      label: 'W/L Preset 8',
      keys: ['8'],
    },
    {
      commandName: 'windowLevelPreset9',
      label: 'W/L Preset 9',
      keys: ['9'],
    },
  ],
  cornerstoneExtensionConfig: {},
  // Following property limits number of simultaneous series metadata requests.
  // For http/1.x-only servers, set this to 5 or less to improve
  //  on first meaningful display in viewer
  // If the server is particularly slow to respond to series metadata
  //  requests as it extracts the metadata from raw files everytime,
  //  try setting this to even lower value
  // Leave it undefined for no limit, suitable for HTTP/2 enabled servers
  // maxConcurrentMetadataRequests: 5,
};
*****************************************************************************************
*****************************************************************************************
NGINX - default.conf
*****************************************************************************************
server {
  listen 80;
 
 location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }

  location  /orthanc/ {
	proxy_pass http://192.168.2.167:49179;
      	proxy_set_header HOST $host;
	proxy_set_header X-Real-IP $remote_addr;
	rewrite /orthanc(.*) $1 break;
	add_header 'Access-Control-Allow-Credentials' 'true';
	add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-	Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
	add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
	add_header 'Access-Control-Allow-Origin' '*';
   }

  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   /usr/share/nginx/html;
  }
}

add these settings to the container definition of your viewer in docker-compose.yml
the APP_CONFIG variable should point to where your viewer config file is located relative to the docker-compose.yml file

environment:
- NODE_ENV=production
- APP_CONFIG=config/viewer.js