<p>I have Nginx Ingress controller deployed in Nginx namespace of my kubernetes cluster.
I am building a custom backend image and deploying it in Nginx namespace as nginx default backend. Now it should serve custom http error pages like 404, 500 and 503etc.</p>

<p>I built one and deployed using helm-chart with below default.conf file but it is serving index.html for 404 error and serving just default 503 error(not my custom 503.html page)</p>

<pre><code>server {
listen 8080 default_server;
root /var/www/html;
index index.html;
location / {
}
location /healthz {
    access_log off;
    return 200 "healthy\n";
}
location /metrics {
    stub_status on;
}
error_page 404 /404.html;
location = /404.html {
    internal;
}
error_page 500 /500.html;
location = /500.html {
    internal;
}
error_page 503 /503.html;
location = /503.html {
    internal;
}
</code></pre>

<p>}</p>

<p>Dockerfile</p>

<pre><code>FROM nginxinc/nginx-unprivileged
USER root
RUN rm /etc/nginx/conf.d/default.conf &amp;&amp; \
ln -sf /dev/stdout /var/log/nginx/access.log &amp;&amp; \
ln -sf /dev/stderr /var/log/nginx/error.log
COPY ./default.conf /etc/nginx/conf.d/default.conf
COPY content/ /var/www/html/
CMD ["nginx", "-g", "daemon off;"]
</code></pre>

<p>Please ask me if you need more info.
Your help will be much appreciated,
Thanks.</p>

<p>To update the default error page, edit the config map of nginx-ingress-controller. Insert a new key  <a href="https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#custom-http-errors" rel="nofollow noreferrer">custom-http-errors</a>  with the HTTP status code that you want to change its error page, such as:</p>

<pre><code>apiVersion: v1  
kind: ConfigMap  
data:  
  custom-http-errors: 404,413,503 
  enable-vts-status: "false"  
metadata:  
  labels:  
    app: nginx-ingress  
    chart: nginx-ingress-1.6.0  
    component: controller  
    heritage: Tiller  
    release: nginx-ingress  
  name: nginx-ingress-controller  
  namespace: Nginx
</code></pre>

<p>Now, fire the test command again,</p>

<pre><code>curl -i "[http://err-test.192.168.64.5.nip.io/err?code=413](http://err-test.192.168.64.5.nip.io/err?code=413)"  
HTTP/1.1 404 Not Found  
Server: nginx/1.15.10  
Date: Sun, 05 May 2019 11:36:04 GMT  
Content-Type: text/plain; charset=utf-8  
Content-Length: 21  
Connection: closedefault backend - 404
</code></pre>

<p>This is  <strong>NOT</strong>  what you want. The Nginx ingress controller correctly captures the HTTP status code that we want to customize. However, the default Nginx “default-backend” <em>(Image: k8s.gcr.io/defaultbackend:1.4)</em> just simply returns 404 status regardless of the actual status code that the application intends to return. This will cause a problem if the status code is to be used for other purposes.</p>

<p>In the <a href="https://kubernetes.github.io/ingress-nginx/deploy/" rel="nofollow noreferrer">Nginx Ingress Controller</a> documentation you may see:</p>

<blockquote>
  <p>The custom backend is expected to return the correct HTTP status code
  instead of <code>200</code>. NGINX does not change the response from the custom
  default backend.</p>
</blockquote>

<p>Then in Dockerfile you have to add path to your defined custom backends errors:</p>

<pre><code>ADD custom-error-pages /  
CMD ["/custom-error-pages"]
</code></pre>

<p>Build the image and push into docker hub. Redeploy the Nginx helm chart in K3s it looks like:</p>

<pre><code>apiVersion: k3s.cattle.io/v1  
kind: HelmChart  
metadata:  
  name: nginx-ingress
  namespace: Nginx
spec:  
  chart: stable/nginx-ingress  
  targetNamespace: kube-system  
  valuesContent: |-  
    defaultBackend:  
      enabled: true  
      name: default-backend  
      image:  
        repository: your-image/custom-error-page  
        tag: latest
</code></pre>

<p>In k8s simply execute:  </p>

<pre><code>helm upgrade nginx-ingress stable/nginx-ingress --set defaultBackendService.enabled=true --set defaultBackend.image.repository=your-image/custom-error-page --set defaultBackend.image.tag=latest
</code></pre>

<p>Then test again, execute the same curl command:</p>

<pre><code>➜ curl -i "[http://err-test.192.168.64.5.nip.io/err?code=413](http://err-test.192.168.64.5.nip.io/err?code=413)"  
HTTP/1.1 413 Request Entity Too Large  
Server: nginx/1.15.10  
Date: Sun, 05 May 2019 12:09:21 GMT  
Content-Type: */*  
Transfer-Encoding: chunked  
Connection: close4xx html
</code></pre>

<p>You will have the custom error page with the correct HTTP status code.</p>

<p>Since you trap 503 status, scale down the replica.</p>

<p>Execute command:</p>

<p><code>$ kubectl scale deploy err-status-test --replicas=0</code></p>

<p>If you will  access the application again, you will see the custom error page with the status code shown as 503 which is expected.</p>

<p>More information you can find here: <a href="https://itnext.io/custom-error-page-for-nginx-ingress-controller-cca4cfa82bb9" rel="nofollow noreferrer">custom-backend-errors</a>.</p>
