Docker label reference
Clearplane discovers proxied services and standalone redirects from Docker labels. Clearplane-owned containers can also read validated runtime settings from labels. See the environment variable reference for bootstrap settings and secrets.
Using an LLM or coding agent? Open the plain-text Docker label reference, the LLM documentation index, or the complete documentation file.
The complete configuration catalog lists every label with its type, accepted values, default, and apply behavior.
Four labels are required to publish a container over HTTPS. The example also includes the optional clearplane.proxy.path label to make its catch-all route explicit.
services:
app:
image: example/app:latest
labels:
clearplane.proxy.enabled: "true"
clearplane.proxy.host: "app.example.com"
clearplane.proxy.port: "8080"
clearplane.proxy.path: "/{**catch-all}"
clearplane.proxy.certificate.enabled: "true"
The example publishes the container on app.example.com, forwards requests to port 8080, and requests an ACME certificate.
How labels apply
The shipped Compose file passes its effective project name to Core. When that setting is omitted, Core resolves the project from the running Core container. Clearplane accepts labels on its own containers only when they belong to the verified project.
Label names mirror the API concepts in kebab-case under their documented hierarchy, and label values keep the same meaning as the corresponding API/UI field. The transport syntax differs only where labels cannot represent the JSON shape directly: lists are whitespace-delimited, nested policy fields use dotted groups such as cache.key, and repeated object entries use indexed labels. The catalog is the canonical name map. Every label value follows these rules:
- Enumerations are written like the REST API and the UI:
On,Prevention,MemoryOnly. Matching ignores case; numeric backing values are not accepted. Fields documented with literal numeric choices, such as redirect status codes, accept those listed numbers instead. - Booleans are
trueorfalse, ignoring case. Anything else, such asyesor1, is invalid. - Lists are whitespace-delimited. When the catalog marks a list as unique, duplicate tokens are invalid; labels do not silently collapse them.
- An invalid runtime-setting value on a Clearplane-owned container is reported as a warning. The setting retains its previous valid label value; when none exists, the invalid label supplies no value and normal source resolution applies.
- An invalid service-resource value rejects the discovered container and keeps its previous route.
An unrecognized owner label on a Clearplane container (clearplane.core.*, clearplane.edge.*, clearplane.ui.*, or clearplane.container-proxy.*) is ignored and reported as a warning. It does not replace or preserve the known runtime label it may have been intended to spell: removing a known label removes its override, so the setting resumes the next source in the documented resolution order.
An unrecognized clearplane.* service-resource key on a discovered application or redirect container rejects that container and keeps its previous route. Unrecognized keys under clearplane.proxy.cache.*, compression.*, error-page.*, group.*, redirect.*, and clearplane.redirect.group.* cannot weaken protection. Clearplane ignores them, builds the route from the remaining labels, and reports each ignored key as a warning in the container's status dialog and in Logs. Cache-key labels (clearplane.proxy.cache.key.*) are the exception: a lost key.headers entry could share responses between users, so an unknown cache-key label rejects the container.
The catalog gives the resolution order. Configuration ownership describes what label changes and removal do to discovered resources, and Policies and scope describes how a route's policy state selects its policies.
Proxy route labels
Apply these labels to an application container that Clearplane should publish.
Match paths
clearplane.proxy.path is the same path field stored in the database and shown by the route UI and REST API. Clearplane preserves the complete route pattern; it does not append or remove segments. The default is /{**catch-all}.
| Value | Matches |
|---|---|
/api |
Only the literal /api path |
/api/{**catch-all} |
/api, /api/orders, and everything below /api |
/{**catch-all} |
Every path on the route's host |
For example:
labels:
clearplane.proxy.path: "/api/{**catch-all}"
The equivalent REST request uses "path": "/api/{**catch-all}", the UI field displays /api/{**catch-all}, and the ProxyRoutes.Path database field stores /api/{**catch-all}.
Policy labels
Every policy family has one root label that sets the route's state for that family:
clearplane.proxy.<family>: Inherit | On | Off # default: Inherit
| Root label | Policies applied to the route | Other clearplane.proxy.<family>.* labels |
|---|---|---|
| missing | Same as Inherit |
Present: the container is rejected. Add clearplane.proxy.<family>: On. |
Inherit |
The family's enabled Global policy or policies, if any | Kept and ignored |
On |
The route's own policies, from <family>.policy or from inline settings. They replace the Global ones. |
Used |
Off |
None, even when a Global policy exists | Kept and ignored |
The families are access-control, authentication, auto-ban, cache, compression, cors, rate-limit, request-headers, response-headers and waf.
<family>.policyreferences existing route-scoped policies by system name. Cache, CORS, compression, request headers, response headers and WAF accept one name. Access control, authentication, automatic bans and rate limit accept a space-separated list.- Inline settings create a policy for this route alone. A setting you leave out takes its documented default; values are never copied from the Global policy.
Onwithoutpolicyor inline settings creates an inline policy with every setting at its default. Authentication is the exception: it has no meaningful defaults, so an inline authentication policy needstypeand its credentials or signing keys.clearplane.proxy.authentication.combine-mode(OrorAnd) is a route setting, not part of a policy, so it can be combined withauthentication.policy.- Combining
policywith inline settings rejects the container, and so does naming a policy twice. - A referenced policy that is disabled stops applying to the route, and discovery reports a warning. The route never falls back to the Global policy.
Reference existing policies:
labels:
clearplane.proxy.access-control: "On"
clearplane.proxy.access-control.policy: "office-only"
clearplane.proxy.authentication: "On"
clearplane.proxy.authentication.policy: "partner-api-keys"
clearplane.proxy.auto-ban: "On"
clearplane.proxy.auto-ban.policy: "scanner-bans"
clearplane.proxy.cache: "On"
clearplane.proxy.cache.policy: "static-assets"
clearplane.proxy.compression: "On"
clearplane.proxy.compression.policy: "web-responses"
clearplane.proxy.cors: "On"
clearplane.proxy.cors.policy: "app-origins"
clearplane.proxy.rate-limit: "On"
clearplane.proxy.rate-limit.policy: "login-throttle api-burst"
clearplane.proxy.request-headers: "On"
clearplane.proxy.request-headers.policy: "tenant-headers"
clearplane.proxy.response-headers: "On"
clearplane.proxy.response-headers.policy: "security-headers"
clearplane.proxy.waf: "On"
clearplane.proxy.waf.policy: "strict-api"
Define a policy inline, or turn a family off for one route:
labels:
clearplane.proxy.cors: "On"
clearplane.proxy.cors.allowed-origins: "https://app.example.com"
clearplane.proxy.rate-limit: "On"
clearplane.proxy.rate-limit.request-limit: "300"
clearplane.proxy.rate-limit.window-seconds: "60"
clearplane.proxy.waf: "Off"
Preserve the original hostname
For applications that strictly validate their public hostname, add this label to the application container:
labels:
clearplane.proxy.preserve-host-header: "true"
Additional hosts and wildcard routes preserve the actual requested hostname. For example, a request for api.example.com:8443 reaches the container with Host: api.example.com:8443.
The label does not change the destination address or disable upstream certificate validation. For routes managed through the UI, enable Preserve host header in the route form.
Upstream activity timeout
To allow up to five minutes of inactivity for one application, add this label to its container:
labels:
clearplane.proxy.upstream.activity-timeout-seconds: "300"
The value is a whole number from 1 through 86400, matching the UI/API activityTimeoutSeconds field. Omitting it uses the documented 60-second default.
Web application firewall — clearplane.proxy.waf.*
Experimental: These settings expose the experimental web application firewall. Use service automatic bans for behavior-based protection.
WAF settings live in WAF policies. A container without clearplane.proxy.waf inherits the enabled Global policy, which is Default WAF in Detection on a new installation, and clearplane.proxy.waf: "Off" opts the route out. With clearplane.proxy.waf: "On", clearplane.proxy.waf.policy assigns an existing Route policy by system name. Otherwise the WAF labels create an inline policy named <route>-waf that the container owns. waf.mode defaults to Detection, which records findings; Prevention blocks.
labels:
clearplane.proxy.waf: "On"
clearplane.proxy.waf.mode: "Prevention"
clearplane.proxy.waf.opt-out-rulesets: "clearplane-scanners"
clearplane.proxy.waf.request-body.maximum-bytes: "4194304"
clearplane.proxy.waf.request-context.header-capture-mode: "RedactSensitive"
The inline policy's labels mirror the policy form, grouped by section:
| Section | Labels |
|---|---|
| Scoring | mode, profile, scoring-mode, threshold, paranoia-level, detection-paranoia-level |
| Rulesets | opt-out-rulesets, exclusion-rulesets, allowed-methods, allowed-request-content-types |
request-body.* |
inspection-mode, maximum-bytes, oversize-action, maximum-spooled-bytes |
websocket.*, grpc.* |
websocket.enabled, websocket.maximum-message-bytes, grpc.maximum-message-bytes, grpc.maximum-messages |
response.* |
inspection, threshold, maximum-body-bytes |
challenge.* |
mode, threshold, difficulty, clearance-minutes |
request-context.* |
enabled and header-capture-mode, which choose what the route's detections record |
The catalog lists each label's accepted values and default.
Disabled rules, target exclusions and per-ruleset thresholds have no labels, because labels cannot address an individual rule. Set them on the inline policy under Firewall → WAF policies; saving there changes only those three, and discovery keeps them when it updates the policy. Every labelled setting stays owned by the container. Opting a whole ruleset out stays a label (clearplane.proxy.waf.opt-out-rulesets).
Caching — clearplane.proxy.cache.*
Caching is a reusable policy. Create Global or Route policies in Performance → Cache policies. One enabled Global policy caches every proxied route that inherits caching; a route's own policy replaces it.
A discovered proxy route can select an existing Route policy by system name:
labels:
clearplane.proxy.cache: "On"
clearplane.proxy.cache.policy: "static-assets"
Omit policy to create an inline policy named <route>-cache from the route's other clearplane.proxy.cache.* labels. A label you leave out takes its catalog default, and an invalid value rejects the container.
A policy with no other settings caches like a CDN. With eligibility: StaticFiles, only paths ending in one of the file-extensions use the cache; the catalog lists the default set, which includes wasm but not html or json. Every other request reaches the upstream and is reported as DYNAMIC. Set eligibility: Everything to cache HTML, API and extensionless paths as well. Under StaticFiles, a response is not stored when its Content-Type is HTML, JSON, XML or plain text and the extension does not name that format, so an application that answers /account/profile.css with the profile page cannot have that page cached (BYPASS / ContentTypeMismatch).
path-rules gives parts of an application their own caching. It is an ordered, whitespace-separated list of pattern=action rules, and the first rule whose pattern matches the request path applies. A pattern starts with /, and * matches any run of characters, including /: /api/* matches /api/ and /api/v1/orders but not /api, and / matches only the root. cache caches the path whatever the eligibility and extensions say, and skips the extension/content-type check. bypass never caches it (DYNAMIC). A cache rule can add ttl=<seconds> to replace the default lifetime and ignore-upstream-cache-control to discard the upstream's lifetime and no-cache. Any rule can add browser-ttl=<seconds> to send Cache-Control: max-age=<seconds> to the client. Per-status lifetimes, bypass cookies, Authorization handling and the private, no-store and Set-Cookie stops still apply.
labels:
clearplane.proxy.cache: "On"
clearplane.proxy.cache.path-rules: "/_framework/*=cache,ttl=31536000,ignore-upstream-cache-control /api/*=bypass /=cache"
Every route that uses a policy shares its storage pool. maximum-total-size-megabytes sizes that pool for all of those routes together, and eviction removes the least recently used entries across the pool. Entries stay separate per route, so one route never serves another route's response. The global per-tier cache limit counts each enabled policy once, however many routes use it. If an inline policy would exceed that limit, Clearplane saves it disabled, keeps the route's cache state On, and reports a warning in the container's status dialog. The route is not cached until capacity is available on a later discovery pass.
A response that declares its own lifetime through Cache-Control, CDN-Cache-Control, Clearplane-CDN-Cache-Control or Expires is clamped into the range between the minimum and maximum lifetimes. A response that declares none is held for the default lifetime, or for a matching status-codes-time-to-live entry. Precedence follows HTTP: s-maxage wins over max-age, which wins over Expires.
Following RFC 9213, an upstream can address Clearplane alone with Clearplane-CDN-Cache-Control. When it is present and valid, its directives replace Cache-Control for Clearplane's lifetime, no-cache, revalidation, stale windows and Authorization consent. CDN-Cache-Control does the same with lower precedence while honor-cdn-cache-control is on. Clearplane-CDN-Cache-Control never reaches the client; CDN-Cache-Control is passed through. private or no-store in Cache-Control still stops storage. The browser-only pattern is Cache-Control: no-cache with Clearplane-CDN-Cache-Control: max-age=3600: Clearplane caches for an hour and answers the browser's revalidations from cache.
An upstream stale-while-revalidate or stale-if-error directive replaces the policy's window for that response. must-revalidate, proxy-revalidate and s-maxage forbid serving a stale copy unless the response also carries one of those stale directives. ignore-upstream-cache-control keeps the policy's windows.
ignore-upstream-cache-control discards a declared lifetime; require-upstream-cache-control caches only responses that declare one. The two cannot both be set. Neither overrides no-store, private or Set-Cookie, which are never stored.
Request cookies neither skip the cache nor enter the cache key, and they still reach the upstream. List cookie names in bypass-cookies to send requests carrying them straight to the upstream; a trailing * matches a name prefix and * alone matches any cookie. A request with Authorization uses and stores only responses the upstream marked public, s-maxage or must-revalidate. A stored response is served to every request that passes the route's access checks, so an upstream that protects static files with its own login cookie must send Cache-Control: private or have that cookie listed in bypass-cookies. A visitor's Cache-Control: no-cache or no-store does not skip the cache unless ignore-request-no-cache or ignore-request-no-store is turned off.
Clearplane answers If-None-Match and If-Modified-Since from the cache with 304 Not Modified and never forwards them when it fills the cache. It revalidates a stale entry, or one stored with no-cache, by sending the entry's ETag and Last-Modified to the upstream; a 304 renews the entry without downloading the body and is reported as REVALIDATED. Requests with If-Match or If-Unmodified-Since bypass the cache, and so do requests carrying X-Original-URL, X-Rewrite-URL, X-HTTP-Method-Override, X-HTTP-Method, X-Method-Override or X-Host, which some frameworks use to serve a different resource than the URL names.
Byte ranges are answered from cache. A GET with a single bytes range receives 206 Partial Content from a stored 200 response, or 416 when the range lies beyond it; a request for several ranges receives the full response. If-Range must match the stored ETag by strong comparison, or equal the stored Last-Modified. When nothing is stored yet, the range request goes to the upstream unchanged (BYPASS / Range), so a video player never waits for the whole file. If the upstream answers 206 with a complete length within maximum-response-size-megabytes, Clearplane fetches the full object in the background, and later ranges are hits.
Clearplane records the tags the upstream lists in Cache-Tag (comma-separated) and Surrogate-Key (space-separated), ignoring case, and removes both headers from client responses. A deploy can then purge every entry carrying a tag, from the cache page, POST /api/cache/purge or clearplane cache purge tag. A response with a tag longer than 1,024 characters or more than 16 KB of tags is not stored (BYPASS / CacheTagLimit), because a partial tag list would let a purge miss it.
With purge-on-redeploy (on by default), Clearplane purges a discovered route's cached responses when discovery sees its container recreated, for example after docker compose up with a new image. A restart of the same container does not purge.
With vary-handling: Honor, Clearplane stores a separate copy for each combination of the request headers the upstream lists in Vary, up to 32 per URL; further combinations reach the upstream without being stored. Ignore stores one copy regardless of Vary. Vary: *, Cookie or Authorization is never stored in either mode. Accept-Encoding and the headers in key.headers are already part of the cache key. For an image that varies on Accept, Clearplane stores one copy per image-format bucket instead of per Accept value: the set of AVIF, WebP and JPEG XL the browser accepts, so at most eight copies. The upstream still receives the browser's own Accept. Add Accept to key.headers to key on the raw value instead.
A cacheable request reaches the upstream with Accept-Encoding reduced to br, gzip, or identity, and Clearplane caches the Brotli, gzip, and plain responses separately, so precompressed assets are fetched once per encoding. When the upstream answers a Brotli or gzip request with a plain body, that plain copy serves every client until it expires. Without a compression policy, requests that bypass the cache keep the client's Accept-Encoding. Compression adds Clearplane's own compression on top.
Compression — clearplane.proxy.compression.*
Compression is a reusable policy, independent from response caching. Create Global or Route policies in Performance → Compression policies. One enabled Global policy can provide the default for every proxied route that inherits compression; a route's own policy replaces it.
A discovered proxy route can select an existing Route policy by system name. A route without clearplane.proxy.compression inherits the Global policy:
labels:
clearplane.proxy.compression: "On"
clearplane.proxy.compression.policy: "web-responses"
In content-types, exclusions always win, regardless of order, and response parameters such as charset=utf-8 are ignored while matching.
With an effective policy, Clearplane reduces the client's Accept-Encoding to the one representation it selected — br, gzip, or identity — and forwards that value upstream. A Brotli or gzip response that matches the forwarded value is served as the upstream sent it, and on a cache-enabled route it is cached under that encoding, so precompressed assets are fetched once per encoding and never compressed again. A plain response is compressed by Clearplane; on a cache-enabled route Clearplane derives compressed copies from the cached plain copy only after the upstream has answered a Brotli or gzip request with it. A plain copy fetched for a client that accepts neither never stands in for the upstream's own compressed file. Clients that accept neither Brotli nor gzip never receive a cached compressed copy; Clearplane asks the upstream for a plain one. A response in any other encoding, including one Clearplane does not support, passes through unchanged and is never cached.
HEAD, bodyless and partial responses, Cache-Control: no-transform, missing or excluded content types, and bodies below the minimum length remain uncompressed. If an effective policy exists and a non-empty body-bearing upstream response is known, Clearplane returns 406 Not Acceptable when the client rejects Brotli, gzip, and identity. When no compression policy applies, Clearplane leaves compression to the upstream service; on a cache-enabled route, cacheable requests still use the reduced Accept-Encoding described under Caching.
Request headers — clearplane.proxy.request-headers.*
Each header transform is a complete indexed entry. Set and Append require value; Remove requires it to be omitted:
labels:
clearplane.proxy.request-headers: "On"
clearplane.proxy.request-headers.entries.1.header-name: "X-Tenant"
clearplane.proxy.request-headers.entries.1.action: "Set"
clearplane.proxy.request-headers.entries.1.value: "example"
clearplane.proxy.request-headers.entries.3.header-name: "X-Legacy"
clearplane.proxy.request-headers.entries.3.action: "Remove"
Standalone redirect labels
Apply these labels to a container that declares an external redirect. The container needs no published port and does not have to join the proxy network. Clearplane answers HTTP-01 challenges before applying the redirect.
services:
old-domain:
image: alpine:latest
command: ["sleep", "infinity"]
labels:
clearplane.redirect.enabled: "true"
clearplane.redirect.source-host: "old.example.com"
clearplane.redirect.additional-source-hosts: "www.old.example.com"
clearplane.redirect.path: "/{**catch-all}"
clearplane.redirect.target-uri: "https://new.example.com"
clearplane.redirect.preserve-path-and-query: "true"
clearplane.redirect.certificate.enabled: "true"
clearplane.redirect.path has the same exact-pattern contract and /{**catch-all} default as clearplane.proxy.path. methods limits the redirect to the listed HTTP methods, and status-code chooses 301, 302, 307 or 308 (default 308). A container cannot enable both clearplane.proxy.enabled and clearplane.redirect.enabled.
Gateway runtime labels
Clearplane's own containers accept runtime settings as labels. A label locks the matching field in System → Settings until you remove it.
- Core container:
clearplane.core.*, for example the Let's Encrypt account, retention periods and country geolocation. - Edge container:
clearplane.edge.*, for example trusted proxies, connection and request limits, cache capacity and the HTTPS protocols (clearplane.edge.http1.enabled,http2.enabled,http3.enabled).
services:
clearplane-edge:
labels:
clearplane.edge.trusted-proxies: "203.0.113.0/24"
clearplane.edge.http1.enabled: "false"
The management UI and API routes are ordinary proxy routes on the Core and UI containers. The shipped Compose file gives both one YAML anchor with their policy labels; set CLEARPLANE_MANAGEMENT_ALLOW_ADDRESSES to the addresses that may reach them. See Exposure and networks.