These settings must match between an application that builds URLs with
image_pipe_url and the image_pipe_server or ImagePipe.Plug that serves
them. A mismatch makes the server reject URLs the builder produced.
Building URLs for the server walks through
setting up both sides.
ImagePipe.Plug takes the builder's settings under the same names: pass
the same keys and source encryption options to ImagePipe.config/1, and a
base_url for URLs it builds itself. Where
a Plug host spells a setting differently, the entry says so.
Signing keys
The hex-encoded HMAC keys that sign each URL. The server's list must hold the first key in the builder's list, which is the one the builder signs with. When neither side has keys, URLs are unsigned. See signing URLs and rotating keys.
Elixir (URL builder)
ImagePipe.URL.config(keys: [System.fetch_env!("IMAGE_PIPE_SIGNING_KEY")])image_pipe_server
[url]
keys = ["0123abcd…"]Or IPS_URL__KEYS=0123abcd…, comma-separated for several keys. See
[url].
On a mismatch:
- A signature that no server key verifies answers
403with the bodyinvalid signature. - An unsigned URL sent to a server with keys answers
403with the bodyinvalid signature. - A signed URL sent to a server without keys answers
400. The body points at thesig=segment withsig is not accepted: no signing keys are configured.
Source encryption keys
The 32-byte keys, written as 64 hex digits, that encrypt the source into an
enc/<token> segment. Generate one with openssl rand -hex 32. The builder
encrypts with the first key. The server decrypts with any key in its list.
See source concealment.
Elixir (URL builder)
ImagePipe.URL.config(
keys: [System.fetch_env!("IMAGE_PIPE_SIGNING_KEY")],
source_encryption_keys: [System.fetch_env!("IMAGE_PIPE_SOURCE_KEY")],
encrypt_source: true
)image_pipe_server
[url]
keys = ["0123abcd…"]
source_encryption_keys = ["89abcdef…"]Or IPS_URL__SOURCE_ENCRYPTION_KEYS=89abcdef…, comma-separated for several
keys. See [url].
encrypt_source (encrypt every source) and iv_mode (whether a source
always encrypts to the same token) are builder settings. The server decrypts
every token without them. Its [url] doesn't accept them, and the server
stops at boot with url.encrypt_source: unknown setting.
Encrypted watermark sources (wm-enc) use the same keys. Encryption keys
without signing keys, or an encryption key equal to a signing key, make
ImagePipe.URL.config/1 and ImagePipe.config/1 raise, and stop
image_pipe_server at boot.
On a mismatch:
- A token that no server key decrypts answers
404with the bodynot found. - An
enc/URL sent to a server without source encryption keys answers400. The body points at the token withenc/ is not accepted: no source encryption keys are configured.
Base URL and mount path
The builder's base_url is the address clients use, including the path the
server serves images under. The signature covers only the path after that
prefix, so the prefix can change without re-signing.
Elixir (URL builder)
ImagePipe.URL.config(base_url: "https://images.example.com/images", keys: keys)image_pipe_server
[server]
mount_path = "/images"The host part of the address comes from DNS, a proxy, or a CDN in front of
the server. With auth_token set in [server], image requests must also
send Authorization: Bearer <token>. [url] doesn't accept base_url, and the server stops at boot
with url.base_url: unknown setting. See
[server].
A Plug host's prefix is the path its router mounts ImagePipe.Plug at, such
as forward "/images", ImagePipe.Plug, …. Its base_url only prefixes URLs
built with ImagePipe.url_config/2. The Plug doesn't check it.
On a mismatch:
- A path outside
mount_pathanswers404with an empty body. - A
base_urlpath longer thanmount_pathleaves extra segments in front of the signature. With signing keys, the request answers403withinvalid signature. Without them, it answers400with the parse error. - With
[server] auth_tokenset, a request without the bearer token answers401with an empty body. A URL can't carry that header, so a browser loading builder URLs gets401unless a proxy or CDN in front of the server adds it.
Preset names
URLs carry preset names, such as preset=card. The server applies its
current definition of each name, so the builder needs no definitions to build
URLs. The signature covers the name only, so changing a definition on the
server keeps signed URLs valid. Define a preset on the server before the app
builds URLs with it, and keep it there while those URLs are in use. The server
answers 400 to a URL with a preset it doesn't have. See
presets.
Elixir (URL builder)
ImagePipe.URL.config(
keys: keys,
validate_against: [
presets: %{"card" => "w=400/h=300/fit=cover"},
request_defaults: "q=80"
]
)validate_against, a copy of the server's presets, request defaults, and
watermark settings, is optional. It lets ImagePipe.URL.validate/1 and
ImagePipe.URL.url/3 check plans against the server's presets, request
defaults, and watermark settings. It never changes a generated URL. preset_lookup: true says the
server resolves names missing from presets with a lookup, so the builder
leaves them to it. See ImagePipe.URL.validate/1.
image_pipe_server
[processing]
request_defaults = "q=80"
[processing.presets]
card = "w=400/h=300/fit=cover"See [processing].
A Plug host defines them as presets: and request_defaults: in
ImagePipe.config/1, and may add a preset_lookup:. Its builder gets them
filled in with ImagePipe.url_config/2.
On a mismatch:
- A name the server doesn't define answers
400. The body points at thepreset=option withunknown preset: card. - A
validate_againstcopy that differs from the server gives wrong validation results in the builder. The URLs stay the same, and the server checks them against its own definitions.
Source prefixes and schemes
The URL carries the whole source string, escaped or encrypted, and the
server routes it by its first path segment or its scheme. The string must
start with a prefix or scheme a server source serves. The source's name
(static in [sources.static]) never appears in URLs. See
routing image paths to sources.
Elixir (URL builder)
ImagePipe.URL.url!(builder, "media/photos/beach.jpg")
ImagePipe.URL.url!(builder, "https://assets.example.com/beach.jpg")image_pipe_server
[sources.media]
adapter = "file"
match = { prefix = "media" }
root = "/data/media"
root_id = "media"
[sources.web]
adapter = "http"
match = { scheme = ["http", "https"] }
allowed_hosts = ["assets.example.com"]See [sources.<name>].
A Plug host configures the same rules as match: in sources: of
ImagePipe.config/1.
On a mismatch:
- A path that no prefix matches, on a server without a
match = "path"source, answers404withsource not found. With amatch = "path"source, that source looks the path up and answers404when nothing is there. - A URL whose scheme no source matches, such as
https://…,s3://…, orasset://…, answers400withinvalid source.
Watermarks
wm=<name> selects a watermark image the server defines. See
watermark assets.
Elixir (URL builder)
config =
ImagePipe.URL.config(
keys: keys,
validate_against: [
presets: %{"card" => "w=400/h=300/fit=cover"},
watermarks: [:logo],
request_watermarks: true
]
)
builder = ImagePipe.URL.new(config)
ImagePipe.URL.group(builder, watermark: :logo)
ImagePipe.URL.group(builder, watermark_source: "brand/badge.png")watermarks and request_watermarks in validate_against
are optional. With watermarks, ImagePipe.URL.validate/1 and
ImagePipe.URL.url/3 check watermark: names against the server's. With
request_watermarks: false, they reject watermark_source:, as a server
without request_watermarks does. true, or leaving it out, lets watermark
sources through. validate_against always checks presets too, so list the
server's presets next to the watermark settings.
image_pipe_server
[processing]
request_watermarks = true
[processing.watermarks.logo]
source = "brand/logo.png"See [processing].
A Plug host defines them as watermarks: and request_watermarks: in
ImagePipe.config/1, and its builder gets both filled in with
ImagePipe.url_config/2. request_watermarks lets URLs name their own
watermark source (watermark_source: in the builder, wm-src64 or wm-enc
in the URL).
On a mismatch:
- A name the server doesn't define answers
400. The body points at thewm=option withunknown watermark. A builder whosevalidate_againstlists the names returns an:unknown_watermarkissue instead of a URL. - A watermark source in the URL, on a server without
request_watermarks, answers400withrequest watermark sources are not enabled. A builder whosevalidate_againsthasrequest_watermarks: falsereturns a:watermark_source_disabledissue instead of a URL.