Kubernetes Ingress 404 Path Rewrite: Configure Custom Error Pages and Fallback Routes
Quick Answer
- What it does: Rewrites unmatched Kubernetes Ingress requests (404 responses) to a custom path, such as an SPA fallback to
index.htmlor a branded error page. - First checks: Confirm your Ingress controller (nginx-ingress, Traefik, HAProxy) supports custom error handling, and verify the annotation or middleware syntax matches your controller version.
- Minimal fix: For nginx-ingress, add
nginx.ingress.kubernetes.io/custom-http-errors: "404"andnginx.ingress.kubernetes.io/error-page-redirect: "/custom-404.html"to your Ingress resource. - Environment boundary: Works with Ingress controllers that implement custom error annotations or middleware; the Ingress API itself is stable but controller-specific features vary by version.
What Problem It Solves
Kubernetes Ingress controllers return a default 404 page when a request doesn't match any defined path rule. This default response is often generic, unstyled, and unhelpful for users. The 404 path rewrite pattern solves several practical problems:
| Scenario | Without Rewrite | With Rewrite |
|---|---|---|
| SPA with client-side routing | Browser shows raw 404 | All unknown routes serve index.html for the router to handle |
| API gateway | Generic "not found" text | Consistent JSON error payload |
| Multi-tenant platforms | Same default page for all hosts | Host-specific branded 404 pages |
| Version migration | Users hit dead endpoints | Redirect to new version or helpful guidance |
The key advantage is handling this at the Ingress layer rather than modifying application code. Your backend services stay unchanged, and the rewrite logic lives in infrastructure configuration.
When This Error or Setup Appears
You'll need 404 path rewriting when:
- You deploy a single-page application (React, Vue, Angular) where the frontend router manages routes, but direct URL access (like
/dashboardor/settings) returns 404 because no backend service matches that path. - You run multiple services behind one Ingress and want unmatched requests to hit a specific fallback service rather than the controller's default error page.
- You're migrating API versions and want old endpoints to redirect to new ones instead of returning bare 404s.
- You operate a multi-tenant cluster where each hostname should show its own branded error page.
The setup applies to clusters using nginx-ingress, Traefik, HAProxy Ingress, or similar controllers that support custom error handling.
Minimal Working Configuration
For nginx-ingress, the minimal configuration uses two annotations on your Ingress resource:
YAMLapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-app-ingress annotations: nginx.ingress.kubernetes.io/custom-http-errors: "404" nginx.ingress.kubernetes.io/error-page-redirect: "/custom-404.html" spec: rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: my-app-service port: number: 80
Apply it with:
BASHkubectl apply -f ingress.yaml
For Traefik, you need a middleware resource instead:
YAMLapiVersion: traefik.containo.us/v1alpha1 kind: Middleware metadata: name: custom-404 spec: errors: status: - "404" query: "/custom-404.html" service: name: error-service port: 80 --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-app-ingress annotations: traefik.ingress.kubernetes.io/router.middlewares: default-custom-404@kubernetescrd spec: rules: - host: example.com http: paths: - path: / pathType: Prefix backend: service: name: my-app-service port: number: 80
Parameters and Environment Variables
The key configuration parameters depend on your Ingress controller:
nginx-ingress annotations:
| Annotation | Value Format | Purpose |
|---|---|---|
nginx.ingress.kubernetes.io/custom-http-errors | Comma-separated codes (e.g., "404,502") | Which HTTP status codes trigger the custom error handling |
nginx.ingress.kubernetes.io/error-page-redirect | Path starting with / (e.g., "/custom-404.html") | Where to redirect the error request |
nginx.ingress.kubernetes.io/error-page-location | Path for the error page location | Alternative to error-page-redirect for serving static error content |
Traefik middleware parameters:
| Field | Type | Purpose |
|---|---|---|
status | List of integers | HTTP status codes that trigger the error handler |
query | String | Path to the error page or service endpoint |
service | Object | Backend service that serves the error response |
Important: These annotations are controller-specific. The Ingress API itself has no standard field for custom error handling. Always verify your controller version supports the annotation you're using.
Root Cause Analysis
The 404 path rewrite works by intercepting the controller's error handling flow:
- Request arrives at the Ingress controller.
- Path matching fails — no rule matches the requested URL.
- Controller generates a 404 response using its default error page.
- With rewrite configured, the controller instead issues an internal redirect to your specified path.
- The redirect request goes through the Ingress rules again, matching your custom error path.
- Your error service or static file serves the custom 404 content.
The redirect loop problem occurs when your rewrite target path also matches a rule that triggers the same rewrite. For example, if your error page path /custom-404.html matches a path: / rule with the same rewrite annotations, the controller will loop indefinitely.
Common Errors and Fixes
404 Not Rewritten — Default Page Still Shows
Cause: The annotation is misspelled, unsupported by your controller version, or the Ingress resource isn't associated with the expected controller.
Fix: Verify the annotation spelling against your controller's documentation. Check the controller version with kubectl get pods -n ingress-nginx and confirm it supports custom error annotations. Inspect controller logs:
BASHkubectl logs -n ingress-nginx deployment/ingress-nginx-controller
Redirect Loop After Rewrite
Cause: The rewrite target path matches an Ingress rule that applies the same rewrite logic.
Fix: Ensure the error page path doesn't match any rule with the rewrite annotations. Use a dedicated path like /errors/404.html and exclude it from other rules, or use pathType: Exact for the error path:
YAML- path: /errors/404.html pathType: Exact backend: service: name: error-service port: number: 80
Ingress Creation Fails with Invalid Annotation
Cause: The annotation key or value format doesn't match what the controller expects.
Fix: Confirm the annotation is supported by your controller. Check that path values start with /. Review controller logs for the specific validation error:
BASHkubectl describe ingress my-app-ingress
Rewritten Request Routes to Wrong Service
Cause: Path matching priority conflicts — the rewritten path matches a different rule than intended.
Fix: Use more specific pathType values (Exact instead of Prefix) and order your rules so the error path takes precedence. Review all Ingress rules in the same namespace for overlapping paths.
Production Notes and Security Checks
When deploying 404 path rewriting in production:
Performance considerations:
- Each rewrite adds an internal redirect, which is negligible for low traffic but can add latency under high load.
- Large numbers of Ingress rules with error annotations can slow down controller configuration reloads.
Security checks:
- Never rewrite 404s to sensitive paths like
/adminor/internal. - Apply access controls to the error page service if it exposes any dynamic content.
- Audit Ingress rules regularly to prevent path traversal attacks where rewritten paths could reach unintended services.
- Always terminate TLS at the Ingress and configure proper certificates for the error page host.
Operational notes:
- Test the rewrite in a staging environment before production rollout.
- Monitor 404 response codes to ensure the rewrite doesn't accidentally mask real errors.
- Document which controller version and annotations your team relies on, since these are not part of the standard Ingress API.
FAQ
Q: How do I configure different 404 rewrite paths for different hostnames?
A: The nginx-ingress annotations are global to the Ingress resource, so you can't differentiate by host within a single Ingress. Create separate Ingress resources per hostname, each with its own annotations and error path. For example, one Ingress for api.example.com rewriting to /api-error.json and another for app.example.com rewriting to /index.html.
Q: How does this compare to using Gateway API?
A: The Ingress API is stable and widely supported across controllers, making it the safer choice for simple 404 rewriting. Gateway API is more powerful and extensible but still evolving, with inconsistent controller support. For this specific use case, Ingress annotations are sufficient and more mature. If you anticipate needing advanced traffic management later, evaluate Gateway API as a future migration path.
Q: Will rewriting 404s affect SEO or user experience?
A: It can improve user experience by showing branded, helpful error pages instead of generic ones. However, you must preserve the HTTP 404 status code in the final response. If your rewrite returns a 200 status, search engines won't recognize the page as missing and may index error content incorrectly. Configure your error service to return the original status code, and add appropriate meta tags to the error page.