Deployment

This page gathers some miscellaneous notes on production deployment.


Temporary Directory

When running in standalone mode, the embedded Jetty server, by default, caches class files in the system temp directory, which most operating systems will periodically clean out. If this happens while the application is running, it can lead to NoClassDefFoundErrors that can only be remedied by restarting the application. Consider either reconfiguring your OS's temp-cleaning strategy to work only at boot or shutdown, or setting the temp_pathname configuration key to use a different location for temporary data.


Images

Some image formats are inherently more efficient to serve than others. If you have control over your source image formats, see the Images section for recommendations.


Health Checks

A health check endpoint is available as part of the HTTP API.


Hardware

CPU

Cantaloupe uses a thread-per-request model, and maintains a thread pool to carry out certain tasks asynchronously and spread work across processors. Response times will benefit from multiple fast cores.

Some source formats are more processor-intensive than others. JPEG2000 via OpenJpegProcessor, for example, will demand much more from a CPU than uncompressed TIFF via Java2dProcessor.

Memory

Memory requirements will vary greatly depending on processors used, source format, source image size, request image size, and request frequency. Image formats that don't support tiling or that can't be selectively decoded will require more memory to process (see Images). The application will log an ERROR-level message if it runs out of memory.

As a Java application, the application runs "sandboxed" inside a Java Virtual Machine (JVM), and can only use the memory the JVM makes available to it. The main area of memory of concern inside the JVM is called the heap, and, unless running in Docker, its size characteristics must be configured at startup using arguments to the java command. The two most important are:

-Xms
Initial heap size. The heap may grow beyond this up to the maximum size, with perhaps a performance penalty during "growth spurts."
-Xmx
Maximum heap size.

The commands in the Getting Started section specify a relatively small maximum heap size, and a production server may need larger.

Operating system utilities like top, Task Manager, Activity Monitor, etc. can show you what a process looks like as the OS sees it, but they can't show what's happening inside a process. A tool like JConsole, included in the Java Development Kit (JDK), can visualize memory usage inside a running JVM.

JConsole screenshot
Screenshot of JConsole

Storage

Most source formats benefit from fast read performance—in terms of both latency and throughput—in the underlying storage system. Throughput is more important for less efficient source formats—like JPEG, PNG, and mono-resolution TIFF—especially as source image size increases. Local filesystem storage usually performs best.

As derivative images tend to be small, storage performance is less important for derivative caches.


Caching

See the Caching section for information about the built-in caching options, which can dramatically improve performance. When using automatic maintenance in a cluster, consider enabling it on only one node.


Limiting

  • Setting the max_scale configuration option to 1.0 will disallow requests for larger scales that could overwhelm the server.
  • A max_pixels configuration option is available to limit the maximum returned size of processed images. This is a "safety net" to prevent excessively expensive requests. It does not affect requests for full-sized unmodified images, which do not significantly load the server.
    • Note that the authorize() delegate method can perform the same function as max_pixels, with more granular control.

Reverse-Proxying

Cantaloupe can run behind a reverse-proxy web server like Apache or nginx. The proxy should be set up to pass-through encoded URI characters without decoding them. It should also be configured to send the following headers:

Header Description Required?
X-Forwarded-Proto Protocol of the client request; either HTTP or HTTPS. If missing, HTTP is assumed. No
X-Forwarded-Host FQDN of the client-facing reverse proxy. Yes
X-Forwarded-Port TCP port of the client-facing reverse proxy. If missing, the following are consulted in priority order:
  1. The port in the X-Forwarded-Host header;
  2. The default port of the protocol in the X-Forwarded-Proto header;
  3. The request port.
No
X-Forwarded-Path Client-facing path. No
X-Forwarded-For Client IP address. If missing, any features that require a client IP address will either not work (such as IP-based authorization), or be incorrect (such as access logs). No
X-IIIF-ID Deprecated since version 4.0. Use X-Forwarded-ID instead. Originally-requested image identifier. Should be set only when the proxy server will change the value of the identifier in the forwarded request; i.e. when the client is asking for a different identifier than the image server ends up seeing. No
X-Forwarded-ID Originally-requested image identifier. Should be set only when the proxy server will change the value of the identifier in the forwarded request; i.e. when the client is asking for a different identifier than the image server ends up seeing. No

If the proxy cannot be configured to send the X-Forwarded-* headers, the base_uri configuration option can be used instead; set it to the URI of the client-facing reverse proxy including any base path.

In a reverse-proxying scenario, consider disabling the access log, if it would be redundant.

Apache

The following example will make an instance running at http://image-server:8182/ available at http://apache-server/.

<VirtualHost *:80>
  # X-Forwarded-Host will be set automatically by the web server.
  RequestHeader set X-Forwarded-Proto HTTP
  RequestHeader set X-Forwarded-Port 80
  RequestHeader set X-Forwarded-Path /

  ServerName apache-server
  AllowEncodedSlashes NoDecode
  ProxyPassReverseCookiePath / /
  ErrorLog logs/image-error.log
  CustomLog logs/image-access.log combined

  ProxyPass / http://image-server:8182/ nocanon
  ProxyPassReverse / http://image-server:8182/
  ProxyPassReverseCookieDomain image-server:8182 apache-server
  ProxyPreserveHost on
</VirtualHost>

nginx

The following example will make an instance running at http://image-server:8182/ available at http://nginx-server/.

location / {
    if ($request_uri ~* "/(.*)") {
        proxy_pass http://image-server:8182/$1;
    }
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Path /;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect http://image-server:8182/ /;
}

SSL/TLS

In standalone mode, Cantaloupe supports TLS connections over HTTPS, configurable via the https.* keys in the configuration file. The general process for getting this working is to add a signed X.509 certificate to either a Java KeyStore (JKS) or PKCS#12 key store, and then refer to the key store file with the https.key_store_path configuration option.

HTTPS can also be enabled on a Servlet container or reverse-proxying web server, in which case Cantaloupe would require no special configuration.


HTTP/2

HTTP/2 is supported since version 3.4 via the http.http2.enabled and https.http2.enabled configuration keys. H2C (unencrypted) works in Java 8, but H2S (encrypted) requires at least Java 9.


Docker

When running in Docker, consider using JRE 8u191 or later. This version includes support for auto-detecting container CPU and memory settings (see JDK 8u191 Update Release Notes) as an alternative to using VM arguments like -Xmx.