Configuration
Everything is configured with environment variables, or with a YAML file named by
CONFIG_FILE. Environment variables win over the file, and both win over the
defaults. A variable that is set but empty counts as unset. The full list is in
Environment variables.
Invalid configuration (an unknown theme or language, random mixed with theme names,
a malformed LINKS value, a bad URL) stops the container at start with a one-line
message instead of rendering broken pages. Check docker logs if it does not come up.
The YAML file
Section titled “The YAML file”Mount a file and point CONFIG_FILE at it:
theme: status # or a list such as "glass,status", or randomlanguages: [en, de]default_language: endefault_page: "404"send_same_http_code: trueshow_details: trueshow_footer: trueshow_version: falsecopyright_name: Example Inc.copyright_url: https://example.comlinks: - id: imprint urls: de: https://example.com/de/impressum en: https://example.com/en/imprint labels: de: Impressum en: Imprint - id: privacy url: https://example.com/privacy labels: de: Datenschutz en: Privacyservices: error-pages: image: noixdev/error-pages environment: CONFIG_FILE: /config/config.yaml volumes: - ./config.yaml:/config/config.yaml:roThe keys are the lower-case names of the environment variables, for example
default_language for DEFAULT_LANGUAGE. Unknown keys are rejected, so a typo is
caught at start. Quote default_page ("404") so that YAML reads it as text.
Footer links
Section titled “Footer links”Links appear in a menu on the page. Each link has:
| Field | Meaning |
|---|---|
id | Required. Unique name of the link; also the fallback label. |
url | One address for every language. |
urls | One address per language, for example de and en. Wins over url. |
labels | The text per language. A missing label falls back to the DEFAULT_LANGUAGE label, then to the id. |
A link needs url, or urls. If you give only urls, it must cover every language
in LANGUAGES. Links open in the same tab, and an empty list shows no menu.
Addresses must start with http:// or https://, or be a path on the same site that
starts with a single /. Anything else (such as javascript: or //host) is
rejected, as are addresses containing spaces or control characters. The same rules
apply to COPYRIGHT_URL.
In the environment, LINKS is a JSON array with the same fields:
LINKS='[{"id":"imprint","url":"https://example.com/imprint","labels":{"en":"Imprint","de":"Impressum"}}]'Footer and details
Section titled “Footer and details”COPYRIGHT_NAMEshows ”© year name” in the footer;COPYRIGHT_URLmakes the name a link.SHOW_VERSIONadds the version, andSHOW_FOOTER=falsehides the footer.SHOW_DETAILSshows the time (UTC), host and request ID. Only thestatustheme displays them. The host comes fromX-Forwarded-Host, elseHost, and the request ID fromX-Request-Id, else a random one per request.
Status codes in the response
Section titled “Status codes in the response”By default a page is answered with its own status code, so bots and monitors see
the truth: the page for 502 comes with status 502. Set SEND_SAME_HTTP_CODE=false
to answer 200 for every page.
Choosing the page
Section titled “Choosing the page”The page is chosen in this order:
- The request path:
/404,/404.html,/internal,/maintenance. - An
X-Coderequest header with a code from 400 to 599, if the path names no page. DEFAULT_PAGEfor any other path.
A path that names a page therefore always wins, so a client cannot change the page a
proxy rewrote its request to by sending its own X-Code.
Clients that ask for JSON get {"code":503,"title":"...","description":"..."} and
clients that ask for plain text get 503 Title, in the detected language. The
Accept header decides, with its quality values: the format with the highest q
wins, a tie or an Accept header without a usable format gives the HTML page, and
q=0 rules a format out. application/json, text/html;q=0 therefore gets JSON.
Maintenance mode
Section titled “Maintenance mode”Maintenance mode replaces every genuine server error page (5xx) with the maintenance page, answered with status 503. Client errors such as 404 are unaffected. It is on when either of these is true:
- the flag file exists (default
/data/maintenance, set withMAINTENANCE_FILE), or MAINTENANCE=trueis set.
Switch it at runtime
Section titled “Switch it at runtime”Use the command line inside the running container. No restart is needed; the server looks at the flag file about once per second.
docker exec error-pages /error-pages maintenance ondocker exec error-pages /error-pages maintenance on --until 2026-12-01T18:00:00Zdocker exec error-pages /error-pages maintenance statusdocker exec error-pages /error-pages maintenance offstatus prints off, on or on until <time>. The command writes the flag file,
so the directory (/data) must exist and be writable. Mount a volume on /data if
the switch should survive the container being recreated:
docker run --name error-pages -v error-pages-data:/data noixdev/error-pagesExpected end time
Section titled “Expected end time”With an end time, visitors see when you expect to be back and the response carries a
Retry-After header. The time is RFC 3339, for example 2026-12-01T18:00:00Z.
maintenance on --until <time>stores the time in the flag file.MAINTENANCE_UNTILsets it for maintenance switched on withMAINTENANCE=true, or for a flag file that holds no time. A time in the flag file wins.- Once the time has passed, the end time is no longer shown or sent, but the maintenance page stays until you switch maintenance off.
Start in maintenance mode
Section titled “Start in maintenance mode”Set MAINTENANCE=true (optionally with MAINTENANCE_UNTIL) to start a container that
way. Switching it off with maintenance off removes the flag file only, so a
container started with MAINTENANCE=true stays in maintenance mode until you
restart it without the variable.