Table of content
December 18, 2025 ยท View on GitHub
Configuration
Mort requires some configuration to run properly. This section aims at basic information about configuration.
Example config:
headers: # add or overwrite response headers of given status. This field is optional
- statusCodes: [200]
values:
"cache-control": "max-age=84000, public"
buckets: # list of available buckets
demo: # bucket name
keys: # list of keys, to access mort over the S3 protocol (optional)
- accessKey: "access"
secretAccessKey: "random"
transform: # config for transforms
path: "\\/(?P<presetName>[a-z0-9_]+)\\/(?P<parent>[a-z0-9-\\.]+)" # regexp for transform path
kind: "presets-query" # type of transform or "query"
presets: # list of presets
small:
quality: 75
filters:
thumbnail:
width: 150
storages:
basic: # retrieve originals from s3
kind: "s3"
accessKey: "acc"
secretAccessKey: "sec"
region: ""
endpoint: "http://localhost:8080"
transform: # and store it on disk
kind: "local-meta"
rootPath: "/var/www/domain/"
Server
Server section describe configuration for the HTTP server and some runtime variables
server:
listen: "0.0.0.0:8080" # default traffic listener
listens: # alternative: multiple listeners (HTTP and Unix sockets)
- ":8084"
- "unix:/tmp/mort.sock"
monitoring: "prometheus" # default no monitoring, or "prometheus" for metrics
logLevel: "info" # log level: debug, info, warn, error (default: info)
accessLogs: true # enable HTTP access logs (default: false)
# Performance & Concurrency
concurrentImageProcessing: 100 # max concurrent image transformations (default: 100)
# Adjust based on CPU/memory capacity
# - Small servers: 20-50
# - Medium servers (4-8 cores): 100-200
# - Large servers (16+ cores): 200-500
requestTimeout: 70 # request processing timeout in seconds (default: 60)
lockTimeout: 30 # lock timeout for collapsed requests in seconds (default: 30)
# Cache Configuration
cache:
type: "memory" # cache type: "memory" (default), "redis", or "redis-cluster"
cacheSize: 50000 # memory cache size limit in bytes
maxCacheItemSizeMB: 50 # max item size to cache in MB (default: 5)
minUseCount: 2 # minimum access count before caching (prevents one-time requests)
# Redis cache config
address:
- "localhost:6379"
clientConfig: # optional redis client configuration
maxRetries: "3"
# Request Collapsing / Lock Configuration
lock:
type: "memory" # lock type: "memory" (default), "redis", or "redis-cluster"
# Redis lock config (for distributed deployments)
address:
- "localhost:6379"
clientConfig: # optional redis client configuration
# Memory Management (optional)
idleCleanup:
enabled: true # enable automatic memory cleanup during idle periods
idleTimeoutMin: 5 # minutes of inactivity before cleanup
# Server Listeners
internalListen: "0.0.0.0:8081" # listener for /debug (pprof) and /metrics (prometheus)
# File Upload
maxFileSize: 104857600 # max file upload size in bytes (default: 100MB)
# Plugins
plugins: # list of additional plugins
webp: ~ # automatic WebP conversion based on Accept header
compress: # response compression
gzip:
types: # MIME types to compress
- text/plain
- application/json
level: 4 # compression level 1-9
brotli:
types:
- text/plain
- application/json
level: 4
Server Configuration Details
Concurrent Image Processing
The concurrentImageProcessing setting controls how many image transformations can run simultaneously. This is crucial for:
- Preventing server overload during traffic spikes
- Memory management - each transformation consumes memory
- CPU utilization - balancing parallel processing with system resources
Recommended values:
- Default (100): Good for most servers with 4-8 CPU cores and 8-16GB RAM
- Low (20-50): Suitable for:
- Small servers or shared environments
- Limited memory (< 4GB RAM)
- Low CPU count (1-2 cores)
- Medium (100-200): Suitable for:
- Dedicated servers with 8-16 cores
- 16-32GB RAM
- Moderate to high traffic
- High (200-500): Suitable for:
- Large servers with 16+ cores
- 32GB+ RAM
- Very high traffic applications
- Very High (1000+): Only for large distributed clusters with significant resources
When the limit is reached, requests return HTTP 503 (Service Unavailable) and clients can retry.
Request Collapsing & Locking
Mort includes a request collapsing mechanism to prevent duplicate processing:
- Memory Lock (default): Uses in-process locking, suitable for single-instance deployments
- Redis Lock: Uses distributed locking via Redis, required for multi-instance deployments
When multiple requests for the same image transformation arrive simultaneously:
- First request acquires the lock and processes the image
- Subsequent requests wait for the result
- Once processing completes, all waiting requests receive the same result
- This prevents the "thundering herd" problem
Redis Lock Features:
- Automatic lock refresh to prevent expiration during long operations
- Configurable lock timeout (default: 30 seconds)
- Pub/sub notification for efficient cross-instance communication
- Proper resource cleanup to prevent goroutine leaks
Important: Always call proper cleanup when shutting down to release Redis connections:
if redisLock, ok := lock.(*lock.RedisLock); ok {
redisLock.Close()
}
Cache Configuration
Response caching significantly improves performance by storing transformed images:
- Memory Cache: Fast, but limited to single instance
- Redis Cache: Shared across instances, suitable for distributed deployments
Cache Strategy:
- Only successful responses (HTTP 200) with known content length are cached
- Configurable maximum item size prevents memory exhaustion
minUseCountprevents caching of rarely-accessed images
Idle Cleanup
The idleCleanup feature automatically releases memory during periods of low activity:
- Frees vips buffer caches
- Runs garbage collection
- Helps maintain stable memory usage over time
Enabled by default with a 5-minute idle timeout.
Response Headers
Overwrite the response headers for a given status code.
headers:
- statusCodes: [200]
values:
"cache-control": "max-age=84000, public"
- statusCodes: [404, 400]
values:
"cache-control": "max-age=60, public"
- statusCodes: [500, 503]
values:
"cache-control": "max-age=10, public"
Buckets
Main configuration for storage and image processing. It contains a list of buckets.
Example buckets config:
buckets:
media:
keys: # s3 keys for this bucket useful for uploading files
- accessKey: "acc"
secretAccessKey: "sec"
transform: # optional configuration for image operations
path: "\\/(?P<presetName>[a-z0-9_]+)\\/(?P<parent>.*)"
kind: "presets"
parentBucket: "media"
resultKey: "hash"
presets:
small:
quality: 75
filters:
thumbnail:
width: 150
storages:
basic:
kind: "http"
url: "https://i.imgur.com/<item>"
headers:
"x--key": "sec"
transform:
kind: "local-meta"
rootPath: "/Users/aldor/workspace/mkaciubacom/web"
pathPrefix: "transforms"
Transform
This section describes, if and what operation can be applied to an image.
There are 3 ways to determine which operation should be applied to an image:
Presets
kind: "presets"
In this kind you have to define a matching regexp for request path (path without bucket name). In this regexp you have to add two matching groups - presetName, parent.
- presetName is a name of preset that should be performed on given image(parent).
- parent is a image original on which we are performing operations
Example usage:
path: "\\/(?P<presetName>[a-z0-9_]+)\\/(?P<parent>.*)"
It will match url http://mort/media/preset/dir/parent.jpg and
- presetName will be - preset
- parent will be - dir/parent.jpg
Query
kind: "query"
This kind of transform determines the operations from the query string. There is no need to provide regexp path.
Example usage:
http://mort/media/dir/parent.jpg?operation=resize&width=1000
Presets-query
kind: "presets-query"
This kind merge presets and query in one kind. It will try to match regexp for path it will not match then it try to parse query string. Like in presets kind regexp is required.
Other options:
parentBucket - this key will add defined name to path of parent when parsing
resultKey - this key will define way of creating transform object unique key. Hash mean that key will be murmur hash from parent and transforms. When empty request path will be used.
parentStorage - change storage from with mort should fetch originals of image
checkParent - flag indicated that mort should always check if original object exists before returning transformation to client
Cloudinary
kind: "cloudinary"
Like for "presets", you also have to define a matching regexp for request path (path without bucket name). In this regexp you have to add two matching groups - transformations and parent. *
- transformations captures the part of path with transformation definiton in a Cloudinary format.
- parent is an image identifier stored in a Basic storage
Example usage:
path: "\\/(?P<transformations>[a-z0-9_]+)\\/(?P<parent>.*)"
Currently a set of supported transformation is limited to following:
- c_fit
- c_fill
Configuring cloudinary transform automatically enables upload support.
Storage
This section define way of fetching object from storage. For fetching original object storage of name basic or defined in parentStorage, for image transformation transforms storage will be used.
List of storage adapters:
- local-meta - adapter working on local file system
- noop - adapter that don't save image and always return that object doen't exists
- http - adapter that call remote storage using HTTP protocol
- s3 - adapter for Amazon S3 compatible service
- azure - adapter for Azure Blob Storage
- b2 - adapter for Black Base
- google - adapter for google storage
- oracle - adapter for oracle storage
- sftp - adapter for sftp
local-meta
Local filesystem storage.
Example definition:
kind: "local-meta"
rootPath: "/Users/aldor/workspace/mkaciubacom/web" # required root path for objects
noop
No operations storage. That does nothing.
Example definition:
kind: "noop"
http
HTTP remote storage. That can only fetch objects.
Example definition
kind: "http"
url: "http://remote/<container>/<item>"
headers:
"x-mort": 1
url - remote address, in url you should provide placeholders for bucket name (conatiner) and item path (item)
headers - additional request headers (optional)
s3
Adapter that fetch object from s3 storage.
Example definition
kind: "s3"
accessKey: "a"
secretAccessKey: "b"
endpoint: "s3.amazonaws.com"
region: "eu-west-1"
bucket: "mybucket" # optional
accessKey - S3 access key
secretAccessKey - S3 secret access key
endpoint - address of S3 service
region = region of s3 service
bucket - bucket used for storage, when empty name of bucket will be used
azure
Example config
kind: "azure"
azureAccount: "account"
azureKey: "key-for-azure"
sftp
kind: "sftp"
sftpHost: "sftp.dev"
sftpPort: 22
sftpUsername: "sftp"
sftpPassword: "pass"
oracle
kind: "oracle"
oracleUsername: "oracle"
oraclePassword: "password"
b2
kind: "b2"
b2Account: "aaa"
b2ApplicationKeyId: "key"
kind: "google"
googleConfigJson: |
{"no-idea": "value"}
googleProjectId: "id"
googleScopes: "a, b"