error-pages
๐ช Tiny, zero-dep HTTP server & Docker image serving pretty, themeable, localized HTTP error pages
10M+
Important
If you were on v3 or earlier and want to upgrade to v4, check out the [migration guide](docs/UPGRADE_TO_V4.md).
If you ended up here, chances are you would like to replace your HTTP server's default error pages with something more original and eye-catching. That is exactly what this project is designed for - it handles this with minimal effort on your part.
It includes:
Key features:
The following templates are built-in and available for use without any additional setup/files:
| Template name | Preview (light) | Preview (dark) |
|---|---|---|
app-down | ![]() | ![]() |
cats | ||
connection | ||
ghost | ||
hacker-terminal | ||
l7 | ||
lost-in-space | ||
noise | ||
orient | ||
shuffle | ||
win98 | ![]() | ![]() |
Note
The `cats` template is the only one of those that fetches resources (the actual cat pictures) from external servers - all other templates are self-contained.
Tip
If you need the **pre-rendered static error pages pack**, you can download it as a [zip][pages-pack-zip] or [tar.gz][pages-pack-tar-gz] archive.
Download the latest binary for your OS/architecture from the releases pageโ , or use the Docker image:
| Registry | Image |
|---|---|
| GitHub Container Registryโ | ghcr.io/tarampampam/error-pages |
| Quay.ioโ (mirror) | quay.io/tarampampam/error-pages |
| Docker Hubโ (mirror) | tarampampam/error-pages |
Warning
Using the `latest` tag for Docker images is strongly discouraged, as it may introduce backward-incompatible changes during **major** upgrades. Use versioned tags in the `X`, `X.Y`, or `X.Y.Z` format instead.
Important
The app is distributed as two separate binaries - `error-pages` (HTTP server) and `builder`. Docker tags follow this convention: - `X.Y.Z` (and `X.Y`, `X`) - includes the HTTP server - `X.Y.Z-builder` (and `X.Y-builder`, `X-builder`) - includes the builder and a pre-rendered error pages pack
Supported image architectures - linux/amd64, linux/arm/v7, linux/arm64, linux/ppc64le, linux/s390x.
All images are signed with Cosignโ using keyless signing (GitHub OIDC).
A Helm chart for Kubernetes is included with each release (downloadโ ), published on Artifact Hubโ , and also available via an OCI registry (Helm v3.8+ required):
helm install error-pages \
oci://ghcr.io/tarampampam/error-pages/charts/error-pages \
--version X.Y.Z
All supported chart values, examples, and usage instructions can be found at Artifact Hubโ .
Helm chart sources are located in the deploy/helmโ directory of the repository.
Standalone server or builder usage:
With Nginx:
With Caddy:
With Traefik:
With Kubernetes:
Measured on loopback (127.0.0.1), single connection, no artificial load
(wrk -t1 -c1 -d5s --latency http://127.0.0.1:8080/..., less is better):
| Format | p50 (typical response time) | p90 (90% of responses complete within this time) |
|---|---|---|
| HTML | 121 ยตs | 262 ยตs |
| JSON | 51 ยตs | 75 ยตs |
| XML | 48 ยตs | 73 ยตs |
| Plain text | 47 ยตs | 68 ยตs |
| HTML + gzip | 2.4 ms | 3.1 ms |
| JSON + gzip | 256 ยตs | 510 ยตs |
Note
HTML responses are large (full rendered template, ~65 KB), which is why gzip compression takes noticeably more time there. JSON/XML/text are compact structured responses, so they are fastest overall.
For detailed instructions on using the HTTP server and the static site generator, including all supported environment variables and usage examples, check the CLI documentationโ .
The three most important things to understand about how the server behaves - how it determines which error page to show, which format to return, and what request context it can expose.
The server picks the HTTP status code from the first matching source:
/404, /404.html, /404.json, /503.xml, etc.X-Code request header--default-error-page (or DEFAULT_ERROR_PAGE, default: 404)The response format is picked from the first matching source:
.html, .htm, .json, .xml, .txtContent-Type request headerX-Format request header (e.g. X-Format: application/json)Accept request headerSupported formats: HTML, JSON, XML, plain text.
The following HTTP endpoints can be used for health checks, monitoring, or other purposes:
| Path | Description |
|---|---|
/healthz, /health, /health/live, /live | Liveness probe - always returns 200 OK |
/version | Returns {"version":"..."} as JSON |
Every error page response includes the following headers automatically:
| Header | Value | Notes |
|---|---|---|
Content-Type | e.g. text/html; charset=utf-8 | Format-dependent |
Content-Length | Response body size in bytes | Always set |
X-Robots-Tag | noindex, nofollow, nosnippet, noarchive | Prevents error pages from being indexed |
Retry-After | 120 | Only for limited set of status codes |
Content-Encoding | gzip | Only when the client sends Accept-Encoding: gzip |
Headers listed in --proxy-headers (default: X-Request-Id, X-Trace-Id, X-Correlation-Id,
X-Amzn-Trace-Id) are copied from the incoming request to the response when present.
By default, the server always responds with HTTP 200, even when rendering error pages. This is the correct behavior when a reverse proxy (Nginx, Traefik, ingress-nginx) intercepts upstream error responses and replaces only the body - the proxy itself sends the original error status code back to the client.
When error-pages is used as a direct backend - e.g. a catch-all route, a Kubernetes default backend, or
standalone testing - it must return the correct status code itself. Enable --send-same-http-code
(or env SEND_SAME_HTTP_CODE=true) to make the HTTP response status match the error code being rendered.
For detailed instructions on using custom templates and localization features, see the templating documentationโ .
Commands:
go generate -skip readme ./... # (re)generate code, except docs
go generate ./... # (re)generate everything
go build ./cmd/error-pages/ && go build ./cmd/builder/ # build both binaries
go test -race ./... # run all tests
golangci-lint run --fix # lint the code and apply any available auto fixes
helm-docs -c ./deploy/helm/ -t README.tpl.md -o README.md # regenerate chart readme file
# run a live reloading server (useful for testing template changes)
watchexec -r -- go run ./cmd/error-pages/ --show-details
# run before every vibe-coding session
your_ai_tool --prompt "explain why AI Coding Agents are doing shit by default"
I want to say a big thank you to everyone who contributed to this project:
Missing a feature? Found a bug you want fixed? Pull requests are welcome - and yes, you are explicitly invited to try implementing it with an AI coding agent.
To give the agent a fighting chance at producing something that fits this codebase, the repo ships an
AGENTS.mdโ - a structured reference covering project layout, build commands, code style, generated
files, hard prohibitions, and the full post-change workflow. It is written for the agent. Most modern agents
pick it up automatically.
Review every single changed line yourself. Understand it. Be able to defend it in code review. If you cannot explain why a line is there and why it is correct, do not open the PR. "The agent wrote it" is not an answer. The author of a PR is the human who opens it, not the model (at least, I hope so).
I write my own code by hand and encourage you to do the same when you can. AI is a tool, not an excuse to skip the thinking. Trust, but verify - and verify hard.
If you encounter any bugs in the project, please create an issueโ in this repository.
This is open-sourced software licensed under the MIT Licenseโ .
Content type
Image
Digest
sha256:03653e7edโฆ
Size
8.4 MB
Last updated
3 days ago
docker pull tarampampam/error-pages:latest-builder