Kubernetes Nginx Ingress Controller Path Routing 404 Error Troubleshooting on Ubuntu 22.04 LTS
Fix Kubernetes Nginx Ingress path-based routing 404 errors on Ubuntu 22.04 LTS. Debug IngressClass, rules, service backend, and controller logs for proper traffic flow.
Fix Kubernetes Nginx Ingress path-based routing 404 errors on Ubuntu 22.04 LTS. Debug IngressClass, rules, service backend, and controller logs for proper traffic flow.
Introduction
Encountering a 404 Not Found error when accessing an application through a Kubernetes Ingress Controller, specifically with path-based routing, is a common but frustrating issue for DevOps engineers. This typically indicates that while your request might be reaching the Nginx Ingress Controller, the controller itself cannot find a matching Ingress rule or a valid backend service for the requested path. This guide provides a highly technical, step-by-step approach to diagnose and resolve such 404 errors on systems running Ubuntu 22.04 LTS with a Nginx Ingress Controller.
Symptom & Error Signature
Users attempting to access an application via a specific URL path configured in a Kubernetes Ingress resource will receive a 404 Not Found error in their browser. This often happens even when the root path (/) or other paths on the same host might be working correctly, or if the service is directly accessible via NodePort or LoadBalancer.
Typical Browser Output: A standard 404 Not Found page, sometimes branded by the Nginx Ingress Controller's default backend if one is configured, or simply the application's own 404 page.
curl Output:
$ curl -v http://your-domain.com/your-app-path
* Trying 203.0.113.10...
* Connected to your-domain.com (203.0.113.10) port 80 (#0)
> GET /your-app-path HTTP/1.1
> Host: your-domain.com
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Thu, 03 Oct 2024 10:30:00 GMT
< Content-Type: text/plain; charset=utf-8
< Content-Length: 23
< Connection: keep-alive
< Server: nginx/1.23.4
< X-Served-By: default-http-backend
<
404 Not Found
* Connection #0 to host your-domain.com left intact
The X-Served-By: default-http-backend header (if present) is a strong indicator that the Nginx Ingress Controller received the request but couldn't find a matching rule for it, forwarding it to its default 404 handler.
Nginx Ingress Controller Logs: When inspecting the logs of the Nginx Ingress Controller pod, you'll typically find entries similar to these for requests resulting in a 404:
203.0.113.1 - [203.0.113.1] - - [03/Oct/2024:10:30:00 +0000] "GET /your-app-path HTTP/1.1" 404 23 "-" "curl/7.81.0" 0.000 "-" "-" -
2024/10/03 10:30:00 [error] 32#32: *12345 no matching ingress rule for "your-domain.com/your-app-path", client: 203.0.113.1, server: 0.0.0.0:80, request: "GET /your-app-path HTTP/1.1", host: "your-domain.com"
The "no matching ingress rule" message is the most direct indicator that the Ingress controller did not find an Ingress resource with a host and path combination that matches the incoming request.
Root Cause Analysis
A 404 error during Kubernetes Ingress path routing usually stems from one or more of these underlying issues:
- Ingress Class Mismatch or Absence: The Ingress controller is configured to watch for specific
IngressClassresources, but your Ingress object either specifies a differentingressClassNameor omits it entirely, causing the controller to ignore it. - Incorrect Path Definition:
pathTypeMisconfiguration: ThepathType(e.g.,Prefix,Exact,ImplementationSpecific) in the Ingress rule does not correctly match the incoming request path.Prefixis often misunderstood, especially with trailing slashes.- Regex Errors: If
pathType: ImplementationSpecificis used with Nginx's regular expression annotations, the regex might be incorrect or not matching. - Missing or Incorrect Path: The specified path in the Ingress resource simply doesn't match the actual URL path being requested.
- Backend Service Issues:
- Service Not Found: The
service.namespecified in the Ingress rule points to a non-existent, misspelled, or incorrectly namespaced Kubernetes Service. - Service Port Mismatch: The
service.port.number(orservice.port.name) in the Ingress rule does not match the actual port exposed by the target Service. - Service Unavailable: The backend Service itself has no healthy endpoints (e.g., all pods are crashing, in Pending state, or scaled to zero).
- Application Path Mismatch: The application within the pod expects a different base path than what the Ingress is forwarding, and no rewrite rules are in place.
- Service Not Found: The
- Nginx Ingress Controller Annotations:
rewrite-targetMisconfiguration: Thenginx.ingress.kubernetes.io/rewrite-targetannotation is incorrectly set, causing the request path to be rewritten to a non-existent endpoint on the backend service.use-regexIssues: Thenginx.ingress.kubernetes.io/use-regexannotation, if used, might be combined with a faulty regular expression in the path.
- External Load Balancer or DNS Configuration: While less common for path 404s, ensuring your external Load Balancer (if applicable) or DNS entries correctly point to the Nginx Ingress Controller's external IP or hostname is a fundamental prerequisite. A 404 from the Ingress controller means it received the request.
- Firewall Rules: Less likely to cause a 404 from the Ingress controller, but ensure no network policies or external firewalls are blocking traffic from the Ingress controller to the backend services on the pod network.
Step-by-Step Resolution
Follow these steps meticulously to pinpoint and resolve the 404 error.
1. Verify Ingress Controller Status and Ingress Class
Ensure your Nginx Ingress Controller is running correctly and that your Ingress resource is being picked up by it.
Check Ingress Controller Pods:
kubectl get pods -n ingress-nginx -l app.kubernetes.io/name=ingress-nginxEnsure all pods are in a
Runningstate. If not, inspect their logs (kubectl logs <pod-name> -n ingress-nginx).Verify IngressClass Definition: First, list your
IngressClassresources:kubectl get ingressclassLook for an
IngressClassthat defines your Nginx controller (e.g.,nginx,nginx-example).Inspect Your Ingress Resource's
ingressClassName:kubectl get ingress <your-ingress-name> -n <your-namespace> -o yamlEnsure the
spec.ingressClassNamefield in your Ingress resource exactly matches the name of an existingIngressClassresource your controller is configured to watch. IfingressClassNameis omitted, and you have a defaultIngressClassdefined (ingressclass.kubernetes.io/is-default-class: "true"annotation), the controller might pick it up. If no default is set, an omittedingressClassNamemight lead to the Ingress being ignored.A common mistake is having a mismatch or typo in
ingressClassName. If the Ingress controller doesn't pick up the Ingress resource, it cannot route traffic for it.Check Ingress Controller Logs for Parsing Errors: The Ingress controller logs will often show if an Ingress resource is being processed or if there are errors parsing its configuration.
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx | grep "Successfully added" kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx | grep "Error processing Ingress"Look for successful additions of your Ingress resource or any related errors.
2. Inspect Ingress Resource Configuration
The most frequent cause of path-based 404s is incorrect path or pathType configuration.
Retrieve and Examine Your Ingress Resource:
kubectl get ingress <your-ingress-name> -n <your-namespace> -o yamlPay close attention to the
spec.rulessection, specificallyhost,http.paths,path,pathType,backend.service.name, andbackend.service.port.number.Example Ingress Configuration:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-app-ingress namespace: my-namespace annotations: # Potentially relevant annotations (see Step 5) # nginx.ingress.kubernetes.io/rewrite-target: /$2 # nginx.ingress.kubernetes.io/use-regex: "true" spec: ingressClassName: nginx # Must match your IngressClass rules: - host: your-domain.com http: paths: - path: /my-app(/|$)(.*) # Example for regex, typically simpler like /my-app pathType: Prefix # Or Exact, or ImplementationSpecific backend: service: name: my-app-service port: number: 80Understand
pathType:Prefix: Matches URL path segments. For/foo, it matches/foo,/foo/, and/foo/bar. A path/matches all URLs. If multiple prefixes match, the longest matching path wins.- Important: A
Prefixpath/foowill match/fooand/foo/bar. If the backend expects/(root), you might need a rewrite (see Step 5).
- Important: A
Exact: Matches the URL path exactly and case-sensitively./fooonly matches/foo, not/foo/or/foo/bar.ImplementationSpecific: The matching behavior depends on the IngressClass. For Nginx, this often implies regex support, especially when combined withnginx.ingress.kubernetes.io/use-regex: "true".
Misunderstanding
pathTypeis a leading cause of 404s. If your application expects requests to its root (/) but your Ingress path is/my-app, apathType: Prefixon/my-appwithout arewrite-targetmeans the request arrives at the backend as/my-app/something, which the application might not handle.
3. Validate Backend Service and Pods
Even if the Ingress rule matches, a faulty backend service will result in a 404 (or 503 if the service has no healthy endpoints).
Verify Service Existence and Configuration:
kubectl get service <my-app-service> -n <my-namespace> -o yamlEnsure
my-app-serviceexists, is in the correct namespace, and itsspec.portssection correctly exposes the port (80in our example) that your application is listening on. Check that theselectormatches your application's pod labels.Check Service Endpoints:
kubectl get endpoints <my-app-service> -n <my-namespace>You should see at least one address listed under
ENDPOINTS. If not, your service selector isn't matching any running pods, or the pods are unhealthy.Inspect Application Pod Status:
kubectl get pods -n <my-namespace> -l app=my-app-labelEnsure pods are
RunningandReady. If they are inCrashLoopBackOff,Pending, orErrorstates, inspect their logs:kubectl logs <my-app-pod-name> -n <my-namespace> kubectl describe pod <my-app-pod-name> -n <my-namespace>Directly Test the Service (Bypass Ingress): This is a critical diagnostic step. Spin up a temporary pod in your cluster and try to
curlyour service directly using its cluster IP or DNS name.kubectl run -it --rm debug --image=busybox:latest -- /bin/sh # Inside the debug pod: wget -O- http://my-app-service.<my-namespace>.svc.cluster.local:80/ # Or for a specific path: wget -O- http://my-app-service.<my-namespace>.svc.cluster.local:80/expected-app-path exitIf this direct call also returns a 404 (or other errors), the problem lies with your application or service configuration, not the Ingress controller.
4. Analyze Nginx Ingress Controller Logs
The controller's logs are invaluable for understanding how it processes requests.
Tail Controller Logs:
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=200 -fWhile tailing, try to access your problematic URL. Look for lines corresponding to your request. Specifically, search for messages like:
no matching ingress ruleserving default backendrewriting request(if annotations are used)- Your request's HTTP status code (e.g.,
404).
Many Ingress controllers log a unique
request_idor similar. If yours does, you can grep for that ID to trace a single request through the logs.
5. Check Nginx Ingress Annotations (Rewrite Rules)
If you're using path-based routing, especially with pathType: Prefix and your application expects a root path, nginx.ingress.kubernetes.io/rewrite-target is crucial.
Examine Annotations:
kubectl get ingress <your-ingress-name> -n <your-namespace> -o yamlLook under
metadata.annotations.Common
rewrite-targetScenario: If your Ingresspathis/my-appand your backend application serves content from its root (/), you likely need a rewrite.- Incorrect (or missing) annotation: Request to
your-domain.com/my-app/foogets sent to backend as/my-app/foo. Backend returns 404 because it expects/foo. - Correct annotation:
In this case, a request toannotations: nginx.ingress.kubernetes.io/rewrite-target: /$1 nginx.ingress.kubernetes.io/use-regex: "true" # Required for regex in path spec: rules: - host: your-domain.com http: paths: - path: /my-app/(.*) # Capture everything after /my-app pathType: ImplementationSpecific # Or Prefix, but ImplementationSpecific + regex is more precise backend: service: name: my-app-service port: number: 80your-domain.com/my-app/foowould be rewritten to/foobefore being sent tomy-app-service.
Misconfigured
rewrite-targetannotations, especially with incorrect regex capture groups ($1,$2, etc.), are a very common cause of 404 errors. Ensure your regex in thepathcorrectly captures the desired part of the URL, and yourrewrite-targetrefers to the correct capture group.- Incorrect (or missing) annotation: Request to
6. Debug with Nginx Configuration in Controller
The Nginx Ingress Controller dynamically generates Nginx configuration files based on your Ingress resources. Inspecting these files directly can reveal exactly how Nginx is processing your paths.
Access the Controller Pod's Shell:
kubectl exec -it <nginx-ingress-controller-pod> -n ingress-nginx -- bash(Replace
<nginx-ingress-controller-pod>with the actual pod name fromkubectl get pods -n ingress-nginx).Inspect Generated Nginx Configuration: Inside the pod, the main configuration is usually at
/etc/nginx/nginx.conf. Included files for specific Ingresses are often in directories like/etc/nginx/conf.d/.cat /etc/nginx/nginx.conf # Or, for specific virtual hosts/locations: cat /etc/nginx/conf.d/default.conf # This might be where your host is defined # Look for server blocks (your-domain.com) and location blocks (/your-app-path)Examine the
serverblock for yourhostand thelocationblock for yourpath. Verify that theproxy_passdirective points to the correct backend service and port, and that anyrewriterules (if annotations are used) are present and correctly formed.Example Snippet to Look For:
server { listen 80; server_name your-domain.com; location ~* ^/my-app/(.*) { # Matches the path regex from Ingress # Possible rewrite rule if annotation was used rewrite ^/my-app/(.*) /$1 break; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://upstream_balancer_my-app-service_80; # Points to the backend service } # ... other locations or default backend ... }If your path or rewrite rules are not present as expected in this configuration, it indicates an issue with how the Ingress controller is interpreting your Ingress resource (Step 2 and 5).
7. Firewall and Security Group Considerations
While less likely to cause a path-specific 404 (as traffic reaches the controller), ensure no network policies or cloud provider security groups are blocking internal cluster traffic.
- Kubernetes Network Policies: If you have Network Policies enabled, ensure they permit traffic from the Nginx Ingress Controller pods to your application's service pods on the relevant ports.
kubectl get networkpolicy -n <your-namespace> - Cloud Provider Security Groups: If your Kubernetes cluster is on a cloud provider (AWS, GCP, Azure), verify that the security group attached to your worker nodes (where the Ingress controller and application pods run) allows traffic on the necessary ports (e.g., 80/443 from Load Balancer, and internal pod network traffic).
By systematically working through these steps, you should be able to identify the precise misconfiguration causing the 404 error in your Kubernetes Ingress path routing setup. Remember to apply changes and re-test after each potential fix.
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.