Appearance
To serve images with an IIIF server you point a compliant image server (most commonly Cantaloupe) at a directory or store of high-resolution master files, expose its HTTP endpoint, and it answers Image API URLs by cropping, scaling and re-encoding each requested region on demand. You do not pre-render thousands of derivatives; the server computes exactly the pixels each viewer asks for. This guide walks the workflow end to end with Cantaloupe.
How does an IIIF image server work?
A viewer requests a URL like /iiif/3/leaf-12r/full/1024,/0/default.jpg. The server parses the identifier, locates the master image, decodes only the resolution level it needs, applies the region crop, resizes to 1024 pixels wide, applies rotation and quality, encodes a JPEG, and streams it back. Because the request is fully described by its URL, the response is deterministic and trivially cacheable. The same identifier with a tiny tile region is what powers smooth deep-zoom panning.
Which server should you pick?
| Server | Language | Strength | Best for |
|---|---|---|---|
| Cantaloupe | Java | Flexible, easy config, plugins | General archives, the default |
| IIPImage | C++ | Very fast, low memory | High-traffic pyramidal TIFF |
| SIPI | C++ | Built-in Knora integration | Specialised RDF stacks |
| Serverless (e.g. serverless-iiif) | Node/Lambda | No servers to patch | AWS-native, bursty load |
Start with Cantaloupe unless you have a measured performance or integration reason not to.
How do you install and configure Cantaloupe?
Cantaloupe ships as a single runnable JAR. A minimal setup:
bash
# Requires Java 17+
wget https://github.com/cantaloupe-project/cantaloupe/releases/download/v5.0.6/cantaloupe-5.0.6.zip
unzip cantaloupe-5.0.6.zip && cd cantaloupe-5.0.6
cp cantaloupe.properties.sample cantaloupe.properties
java -Dcantaloupe.config=cantaloupe.properties -Xmx2g -jar cantaloupe-5.0.6.jarThe two settings that matter most in cantaloupe.properties:
properties
# Where master images live and how identifiers map to files
source.static = FilesystemSource
FilesystemSource.BasicLookupStrategy.path_prefix = /data/masters/
# Disk cache so derivatives are computed once
cache.server.derivative = FilesystemCache
FilesystemCache.pathname = /var/cache/cantaloupeThen confirm it is alive by fetching info.json.
How do you prepare source images for performance?
Flat JPEGs work but punish the server, which must decode the entire file for every tile. Convert masters to pyramidal, tiled formats so the server reads only the level it needs:
bash
# Tiled, pyramidal TIFF with libvips (fast, low memory)
vips tiffsave master.tif leaf-12r.tif \
--tile --pyramid --compression deflate --tile-width 256 --tile-height 256For a 400-megapixel scan, this single change can cut average response time by an order of magnitude.
How do you check your endpoint is compliant?
Request the metadata endpoint and read it:
bash
curl -s https://images.example.org/iiif/3/leaf-12r/info.json | jq .You should see a valid @context, an id, the image width/height, and a tiles array. Then run the official IIIF Image API validator against the same identifier to catch level conformance gaps before users do.
Where should caching and TLS live?
Put NGINX or a CDN in front of Cantaloupe. Because every Image API URL is deterministic, cache responses aggressively with a long Cache-Control and let the origin compute each derivative once. Terminate HTTPS at the proxy, set permissive but correct CORS headers (viewers on other domains need them), and your server stays lean while the cache absorbs traffic.
What are the common pitfalls?
- Serving flat JPEG masters and wondering why deep zoom is sluggish.
- Forgetting CORS headers, so cross-domain viewers silently fail to load.
- Under-provisioning the JVM heap, causing out-of-memory errors on huge images.
- Skipping the derivative cache, so the server recomputes identical tiles forever.
- Hardcoding the public base URL wrong, so info.json advertises unreachable image URLs.
Key Takeaways
- An IIIF server computes derivatives on demand from master images; you do not pre-render everything.
- Cantaloupe is the safe default; IIPImage wins on raw throughput.
- Convert masters to pyramidal tiled TIFF or JPEG2000 for big performance gains.
- Validate with info.json plus the official IIIF Image API validator.
- A reverse proxy or CDN handles caching, TLS and CORS so the origin stays light.
- Misconfigured CORS and flat source images are the two most common failures.
Frequently Asked Questions
What does an IIIF image server actually do?
It receives Image API URLs, reads a source master image, and dynamically crops, scales, rotates and re-encodes the requested region on the fly. You never pre-generate every derivative; the server computes them per request.
Which IIIF server should I choose?
Cantaloupe (Java) is the most common general-purpose choice; IIPImage (C++) is fastest for pyramidal TIFF at scale; image servers like SIPI or serverless options suit specific stacks. Cantaloupe is the safest default for most archives.
What source image format performs best?
Pyramidal, tiled formats: either tiled multi-resolution TIFF or JPEG2000. They let the server read only the resolution and tile it needs instead of decoding a flat 400-megapixel file each request.
Do I need a IIIF server to publish IIIF?
Not strictly. You can pre-generate static tiles conforming to a fixed Image API level, but a dynamic server gives arbitrary regions, sizes and rotations and is simpler to maintain for large or growing collections.
How do I verify my server is compliant?
Request the info.json endpoint for an identifier and check it returns valid JSON with the correct @context and a sane sizes/tiles block, then run the official IIIF validator against the endpoint.
Where should the heavy lifting of caching happen?
Put a reverse proxy or CDN in front. Image API URLs are deterministic and cacheable, so a cache absorbs repeat requests and lets the server compute each derivative only once.