I was trying to get nice error pages, when my kubernetes service is not working (replicas: 0
). So I found the following resources:
- https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/customization/custom-errors
- https://github.com/kubernetes/ingress-nginx/tree/master/images/custom-error-pages
- https://tech.holidayextras.com/custom-error-handling-with-the-kubernetes-nginx-ingress-controller-f7861b08ffd7
The custom-error-pages
Go sources need to be compiled, which I tried to avoid. So I searched for a prebuilt Docker image and I found one on quay.io:
But, quay.io complained about some security risks in the image, so I searched for another solution. My idea was to get a similar solution with a standard nginx
web server.
Needed features:
- Serve a nice custom error page with css
- Serve a json reply when called with
Accept: application/json
- Return the error code given for nginx ingress controller in the header
X-Code
- The served error page should depend on the error code (4xx vs. 5xx)
After some research, I came up with the following solution:
server {
listen 0.0.0.0:8080;
server_name default;
root /app;
location /healthz {
return 200 "ok";
}
location /status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
set $uri_and_code "${http_x_original_uri}${http_x_code}";
set $type "html";
if ($http_x_format = 'application/json') {
set $type "json";
}
error_page 403 404 /4xx.${type};
error_page 500 502 503 504 /5xx.${type};
location /4xx { internal; }
location /5xx { internal; }
location / {
if ($http_x_original_uri = '') { return 404; }
if ($uri_and_code = '/403') { return 403; }
if ($uri_and_code = '/404') { return 404; }
if ($uri_and_code = '/502') { return 502; }
if ($uri_and_code = '/503') { return 503; }
if ($uri_and_code = '/504') { return 504; }
try_files $http_x_original_uri $uri $uri/ =404;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
log_not_found off;
}
location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
}
I'm not fully satisfied, because it relies on if
statements in location /
(ifisevil).
Is there a better solution?
Cheers,
floek