Kubernetes Ingress Not Routing

Causes and Fixes

Ingress Not Routing occurs when an Ingress resource is created but traffic is not being directed to the expected backend Service. Requests either return 404, hit the wrong backend, or never reach the cluster. This is commonly caused by missing ingress controller, incorrect rules, or misconfigured annotations.

Symptoms

  • HTTP requests to the Ingress hostname return 404 Not Found
  • Traffic reaches the ingress controller but is not forwarded to the backend
  • Ingress shows ADDRESS as empty in kubectl get ingress
  • DNS points to the correct IP but requests fail
  • Only some paths work while others return 404
  • TLS termination fails or certificate errors appear

Common Causes

1
No ingress controller installed
Ingress resources are just configuration objects — they do nothing without an ingress controller like NGINX, Traefik, or AWS ALB Controller watching for them and programming the actual routing.
2
Wrong IngressClass specified
The Ingress resource specifies an IngressClass that does not match the installed controller, or no IngressClass is set and the controller does not handle unclassed Ingresses.
3
Backend Service has no endpoints
The Service referenced in the Ingress backend has no ready endpoints, so the ingress controller has no targets to forward traffic to.
4
Incorrect path or pathType configuration
The path rules do not match the incoming request paths, or the pathType (Exact, Prefix, ImplementationSpecific) does not behave as expected.
5
Host header mismatch
The Ingress rule specifies a hostname but the client request uses a different Host header, IP address, or different domain, so no rule matches.
6
Ingress controller misconfiguration
The ingress controller itself has configuration issues such as wrong service type, incorrect annotations, or missing RBAC permissions to watch Ingress resources.

Step-by-Step Troubleshooting

Ingress routing issues can stem from the ingress controller, the Ingress resource configuration, the backend Service, or DNS. This guide works through each layer to identify where the routing chain breaks.

1. Verify an Ingress Controller Is Installed

Ingress resources do nothing without an ingress controller watching for them.

# Check for common ingress controllers
kubectl get pods --all-namespaces | grep -E 'ingress|traefik|contour|haproxy'

# Check for IngressClass resources
kubectl get ingressclass

If no ingress controller is found, you need to install one. For example, to install the NGINX ingress controller:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/cloud/deploy.yaml

Verify the controller is running and has an external IP or NodePort.

kubectl get service -n ingress-nginx ingress-nginx-controller

2. Check the Ingress Resource

Examine the Ingress configuration for obvious issues.

kubectl get ingress <ingress-name> -o wide

kubectl describe ingress <ingress-name>

Key things to look for:

  • ADDRESS: Should show the ingress controller's external IP. If empty, the controller has not processed this Ingress.
  • Rules: Host and path rules should match your expected routing
  • Backend: Each rule should reference a valid Service name and port
  • Class: Should match your installed IngressClass
# Check the full Ingress spec
kubectl get ingress <ingress-name> -o yaml

3. Verify IngressClass Assignment

If the Ingress has no ADDRESS and the controller is running, the IngressClass may not match.

# Check what IngressClass the Ingress uses
kubectl get ingress <ingress-name> -o jsonpath='{.spec.ingressClassName}'

# List available IngressClasses and their controllers
kubectl get ingressclass -o custom-columns=NAME:.metadata.name,CONTROLLER:.spec.controller,DEFAULT:.metadata.annotations.ingressclass\.kubernetes\.io/is-default-class

If the Ingress specifies a class that does not exist, or if no class is specified and there is no default IngressClass, the controller will not process it.

# Fix by setting the correct IngressClass
kubectl patch ingress <ingress-name> --type=merge -p '{"spec":{"ingressClassName":"nginx"}}'

4. Check Backend Service and Endpoints

The Ingress routes traffic to a Service, which must have healthy endpoints.

# Get the backend service name from the Ingress
kubectl describe ingress <ingress-name> | grep -A2 "Rules"

# Check the Service
kubectl get service <backend-service-name>
kubectl get endpoints <backend-service-name>

If endpoints are empty, see the endpoints-not-found troubleshooting guide. The ingress controller cannot route traffic to a Service with no backends.

5. Test Path Matching

Path matching depends on the pathType field and can be unintuitive.

kubectl get ingress <ingress-name> -o jsonpath='{range .spec.rules[*].http.paths[*]}Path: {.path} Type: {.pathType} -> {.backend.service.name}:{.backend.service.port.number}{"\n"}{end}'

The three pathType values behave differently:

  • Exact: Matches only the exact path (e.g., /api does not match /api/users)
  • Prefix: Matches the path prefix on path element boundaries (e.g., /api matches /api and /api/users but not /apikeys)
  • ImplementationSpecific: Behavior depends on the ingress controller

Test with curl to verify which paths match.

# Test the exact path
curl -H "Host: <hostname>" http://<ingress-ip>/api

# Test a sub-path
curl -H "Host: <hostname>" http://<ingress-ip>/api/users

# Test the root
curl -H "Host: <hostname>" http://<ingress-ip>/

6. Verify Host Header Matching

If the Ingress defines host-based rules, the request must include the correct Host header.

# Test with the correct Host header
curl -v -H "Host: myapp.example.com" http://<ingress-ip>/

# Compare with no Host header (will hit the default backend or return 404)
curl -v http://<ingress-ip>/

If using DNS, verify it points to the ingress controller's IP.

nslookup myapp.example.com
dig myapp.example.com

7. Check Ingress Controller Logs

The ingress controller logs reveal whether it has processed the Ingress and how it handles incoming requests.

# For NGINX ingress controller
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=100

# Look for configuration reload messages
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx | grep -i "reload\|backend\|upstream"

# Check for errors processing the Ingress
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx | grep -i error

If the controller logs show it rejected the Ingress or failed to update its configuration, the logs will contain the specific reason.

8. Inspect the Controller's Generated Configuration

For NGINX-based controllers, you can view the generated nginx.conf to verify the routing is configured correctly.

# View the generated NGINX config
kubectl exec -n ingress-nginx <ingress-controller-pod> -- cat /etc/nginx/nginx.conf | grep -A20 "server_name myapp.example.com"

# Check upstream backends
kubectl exec -n ingress-nginx <ingress-controller-pod> -- cat /etc/nginx/nginx.conf | grep -A10 "upstream"

This shows exactly how the controller translated your Ingress rules into its internal routing configuration.

9. Check TLS Configuration

If the Ingress uses TLS, verify the certificate and secret.

# Check TLS section of the Ingress
kubectl get ingress <ingress-name> -o jsonpath='{.spec.tls}' | jq .

# Verify the TLS secret exists
kubectl get secret <tls-secret-name>

# Inspect the certificate
kubectl get secret <tls-secret-name> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout | grep -E "Subject:|Issuer:|Not After"

Certificate issues include expired certificates, certificates that do not match the Ingress hostname, and missing secrets.

10. Verify Routing Is Working

After making corrections, test the full routing chain.

# Check the Ingress has an ADDRESS
kubectl get ingress <ingress-name>

# Test end-to-end
curl -v -H "Host: <hostname>" http://<ingress-ip>/

# Test with HTTPS if TLS is configured
curl -v https://<hostname>/

# Verify the response comes from the correct backend
curl -s -H "Host: <hostname>" http://<ingress-ip>/ | head -20

A working Ingress setup will have an ADDRESS assigned, the controller logs will show successful configuration reloads, and requests with the correct Host header will be routed to the correct backend Service and receive responses from the application pods.

How to Explain This in an Interview

I would explain the Ingress architecture: Ingress resources define routing rules, IngressClass links rules to a specific controller, and the ingress controller (a pod running a reverse proxy) watches for Ingress resources and configures itself accordingly. I'd discuss how the controller reads the rules, resolves backend Services to endpoints, and programs routing. I'd walk through the common pitfalls — missing controller, IngressClass mismatch, pathType semantics, and host-based routing — and explain how to debug by checking the controller's configuration and logs. I'd also mention the newer Gateway API as an alternative to Ingress.

Prevention

  • Verify the ingress controller is running before creating Ingress resources
  • Always specify the IngressClass explicitly in Ingress resources
  • Test Ingress rules with curl using the Host header before updating DNS
  • Monitor ingress controller logs and metrics for routing errors
  • Use consistent path conventions and document pathType expectations

Related Errors