kubernetes-ingress-defaultbackend

A minimal fallback service that handles all requests an ingress controller cannot route — returning 404 at / and 200 at /healthz.

ingress-nginx/controller, ingress-nginx/custom-error-pages, traefik, haproxy-ingress

What is kubernetes-ingress-defaultbackend?

The kubernetes-ingress-defaultbackend image is a minimal HTTP server that acts as the catch-all backend for Kubernetes ingress controllers. When an incoming request doesn't match any rule defined in an Ingress resource — whether because of an unknown host, an unmapped path, or a misconfigured route — the ingress controller forwards it to the default backend instead of returning an unhandled error.

The image implements a simple two-endpoint contract that the ingress controller expects: /healthz returns an HTTP 200 for liveness probes, and / returns an HTTP 404 for all unmatched traffic. It is a drop-in replacement for the upstream registry.k8s.io/defaultbackend image used by ingress-nginx and ingress-gce, and runs as a non-root user. It has no application logic — it is intentionally as small and inert as possible, since its only job is to absorb unrouted traffic gracefully.

It is relevant to any team running ingress-nginx or a compatible ingress controller that wants a hardened, CVE-free fallback rather than the upstream image.

How to use this image

The default backend is deployed as a Deployment and Service alongside the ingress controller, and referenced via the controller's --default-backend-service flag. The most common path is to override the image when installing ingress-nginx via Helm.

Install ingress-nginx with a custom default backend image:

# values.yaml
defaultBackend:
  enabled: true
  image:
    repository: registry.echo.ai/kubernetes-ingress-defaultbackend
    tag: latest
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
  -f values.yaml --wait
To deploy it standalone as its own Deployment and Service:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: default-backend
  namespace: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: default-backend
  template:
    metadata:
      labels:
        app: default-backend
    spec:
      containers:
        - name: default-backend
          image: registry.echo.ai/kubernetes-ingress-defaultbackend:latest
          ports:
            - containerPort: 8080
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 30
            timeoutSeconds: 5
          resources:
            limits:
              cpu: 10m
              memory: 20Mi

Once deployed, all unmatched ingress traffic is absorbed by this container, which responds with a clean 404. The controller is pointed to it via --default-backend-service=ingress-nginx/default-backend.

Image variants

Published under registry.echo.ai/kubernetes-ingress-defaultbackend, the image is intentionally minimal and ships in two variants:

  • kubernetes-ingress-defaultbackend:latest — Tracks the most recent stable build. Since this image has no application logic and no dependencies to upgrade, latest is acceptable for most deployments.
  • kubernetes-ingress-defaultbackend:<version> — Version-pinned tags for teams that require reproducible, auditable deployments or operate in environments where floating tags are disallowed by policy.

The image runs as a non-root user out of the box and contains no shell or package manager, minimising the attack surface of what is effectively a publicly reachable endpoint in every cluster that uses it.

Interested in base images that start and stay clean?