Based on ingress-nginx's custom error pages backend, with some improvements:
- Added a new build system, based exclusively on Dockerfile, instead of old Makefile-based one (see Build section).
- Implemented support for MIME types which resolves to more than one file
extension (original project uses the first one given by
mime.ExtensionsByType
, i.e. random). - Consequently, fixed bug with random
404 page not found
error instead of your nice HTML error pages (caused byhtml
vshtm
ambiguity). - Added support for Go template engine, which allows you to use some special
headers given by ingress-nginx (such as
X-Namespace
) to alter page contents. See in Build section how to enable it.
Place them under rootfs/www
. Main points:
- Use lowercase in file names.
- Name pages according to HTTP status codes.
- If page for exact code (for example,
501.html
) is absent, server will try to use "more general" name ("3xx" for redirections, "4xx" for client errors, "5xx" for server errors). If it is also absent, "404" will be returned. - If client declares
Accept
(and ingress-nginx setsX-Format
) header different thantext/html
, server will try to found and serve pages with appropriate extension, according torootfs/etc/mime.types
. - If you want to edit
mime.types
, please note that some file extenstions are hardcoded in Go, so you cannot remap or get rid of them by simply editingmime.types
. - If content type is unknown or corresponding files are absent,
*.html
/*.htm
files will be used. - Backend server will run under non-privileged user (UID 101 by default, you
can change it via
--build-arg=UID=XXX
parameter indocker build
command), so, in the case of runtime errors, make sure that your files and directories are accessible to non-owner and non-group users for reading (chmod -R o=rX rootfs
).
You can use template engine (disabled
by default, see in Build section how to enable it). Templating
settings are declared in file src/templating_settings.go
, in Templating
map.
For example,
"text/html": {
enableVar: "TEMPLATE_HTML",
escapeType: escapeHTML,
},
means that for HTML pages (*.html
and *.htm
) template will be used only
if environment variable TEMPLATE_HTML
set to any non-empty value (on/off
switch), and substituted values will be escaped with
html/template
semantical escaping. Another escape option is escapeJSON
, it simply uses
JSEscapeString function.
And, of course, you can always disable escaping for given MIME type via
escapeNone
value.
List of accessible values can be seen in src/constants.go
in Headers
map.
Key is "pretty" name, which will be used in the template as the variable name,
and value is the canonical HTTP header name. For example, the content of
X-Original-URI
header (must be populated by ingress-nginx while proxying
request to this backend) can be referenced in the template as
{{.OriginalURI}}
.
Building version x.y without template engine:
docker build . -t "your-repo/default-backend:x.y"
Building version x.y with template engine:
docker build . -t "your-repo/default-backend:x.y" --build-arg="TAGS=template"
---
apiVersion: v1
kind: Service
metadata:
name: default-backend
namespace: ingress-nginx
labels:
app: default-backend
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: default-backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: default-backend
namespace: ingress-nginx
labels:
app: default-backend
spec:
replicas: 1
selector:
matchLabels:
app: default-backend
template:
metadata:
labels:
app: default-backend
spec:
containers:
- name: default-backend
# Any image is permissible as long as:
# 1. It serves a 404 page at /
# 2. It serves 200 on a /healthz endpoint
# image: gcr.io/google_containers/defaultbackend:1.4
image: "your-repo/default-backend:x.y"
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
ports:
- name: http
containerPort: 8080
Then you can set it as your default HTTP backend for all your namespaces via
--default-backend-service=ingress-nginx/default-backend
ingress-nginx command
line option (to be clear, form is $NAMESPACE/$SERVICE
).
If you want to use specific error pages for some ingresses, create default-backend deployment and service in their namespaces, and add
nginx.ingress.kubernetes.io/default-backend: default-backend
annotation to these ingresses (see documentation).
Also don't forget that custom error pages will be used only for HTTP statuses listed in nginx.ingress.kubernetes.io/custom-http-errors annotation (per ingress) or in custom-http-errors ingress-nginx main ConfigMap setting (global).