1. Introduction
A Kubernetes Ingress resource that isn't routing traffic is one of those failures that can stem from any of five completely different root causes — and the error message is usually just a timeout or connection refused, with no indication of which layer broke. You might have deployed the Ingress resource correctly but the controller isn't watching it, or the controller is running but the Service it's targeting has no ready endpoints, or TLS is misconfigured and HTTPS is silently failing.
This guide covers the complete diagnostic path: verifying the Ingress controller is running, confirming the Ingress has an address, checking backend Service and pod health, and debugging TLS and annotation issues.
2. What "Ingress Not Working" Can Mean
In Kubernetes, an Ingress resource is just a configuration object — it doesn't route traffic by itself. An Ingress controller (NGINX Ingress Controller, AWS Load Balancer Controller, Traefik, etc.) reads Ingress objects and configures an actual load balancer or proxy. If the controller isn't running, isn't watching the right class, or has misconfigured permissions, the Ingress resource exists in Kubernetes but has no effect.
3. Common Causes
- No Ingress controller is installed in the cluster
- Ingress class mismatch — the Ingress specifies a class the installed controller isn't watching
- The Ingress has no
ADDRESS— controller failed to provision the load balancer - Backend Service doesn't exist or is in the wrong namespace
- Backend Service has no ready endpoints (pods are not passing health checks)
- TLS secret doesn't exist or has incorrect certificate/key data
- For AWS ALB Controller: missing subnet tags or insufficient IAM permissions
- Path type mismatch —
ExactvsPrefixcauses mismatched routing - DNS not pointing to the Ingress address
4. Step-by-Step Diagnosis and Fix
Step 1: Confirm the Ingress has an address
# Check if the Ingress has been assigned an address
kubectl get ingress -n <namespace>
# Output should show an ADDRESS — if empty, the controller hasn't provisioned it
# NAME CLASS HOSTS ADDRESS PORTS AGE
# my-ingress nginx app.example.com 203.0.113.1 80,443 5m
# If ADDRESS is empty:
kubectl describe ingress my-ingress -n <namespace>
# Look at Events section for controller error messages
Step 2: Check the Ingress controller is running
# For NGINX Ingress Controller
kubectl get pods -n ingress-nginx
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=50
# For AWS Load Balancer Controller
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl logs -n kube-system deployment/aws-load-balancer-controller --tail=50
# For Traefik
kubectl get pods -n traefik
kubectl logs -n traefik deployment/traefik --tail=50
Step 3: Verify the Ingress class annotation
# View current Ingress spec
kubectl get ingress my-ingress -n <namespace> -o yaml
# Kubernetes 1.18+: use spec.ingressClassName
spec:
ingressClassName: nginx # must match the IngressClass resource name
# Or use the annotation (older approach, still works)
metadata:
annotations:
kubernetes.io/ingress.class: nginx
# List available IngressClass resources in the cluster
kubectl get ingressclass
# NAME CONTROLLER PARAMETERS AGE
# nginx k8s.io/ingress-nginx <none> 10d
Step 4: Verify the backend Service exists and has endpoints
# Check the Service referenced in the Ingress
kubectl get service my-service -n <namespace>
# Check that the Service has endpoints (pods are ready)
kubectl get endpoints my-service -n <namespace>
# If ENDPOINTS is <none> — the Service selector doesn't match any running pods
kubectl describe endpoints my-service -n <namespace>
# Verify the pod selector matches
kubectl get pods -n <namespace> -l app=my-app # use your actual label selector
# All pods should be Running 1/1
Step 5: Test connectivity to the backend Service directly
# Bypass the Ingress and test the Service directly using a debug pod
kubectl run debug --image=curlimages/curl --rm -it --restart=Never -- curl -s http://my-service.<namespace>.svc.cluster.local:<port>/health
# Or test via port-forward to the Service
kubectl port-forward service/my-service -n <namespace> 8080:80 &
curl http://localhost:8080/health
# Expected: 200 response from your application
# If this fails, the problem is in the backend, not the Ingress
Step 6: Check TLS configuration
# Verify the TLS secret exists in the correct namespace
kubectl get secret my-tls-secret -n <namespace>
# Check the secret has the correct keys
kubectl get secret my-tls-secret -n <namespace> -o jsonpath='{.data}' | jq 'keys'
# Expected: ["tls.crt", "tls.key"]
# Verify the Ingress TLS config references the right secret and host
kubectl get ingress my-ingress -n <namespace> -o jsonpath='{.spec.tls}'
# Expected: [{"hosts":["app.example.com"],"secretName":"my-tls-secret"}]
# Check the certificate is valid and not expired
kubectl get secret my-tls-secret -n <namespace> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates -subject
Step 7: Check path type and routing rules
# View the Ingress routing rules
kubectl get ingress my-ingress -n <namespace> -o yaml | grep -A 20 "rules:"
# Common path type issues:
# Exact: only matches /api exactly, not /api/users
# Prefix: matches /api and everything under it
# For SPAs that need all paths to go to one Service:
spec:
rules:
- host: app.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 3000
- path: /
pathType: Prefix
backend:
service:
name: spa-service
port:
number: 80
# Also check for the SPA routing fix: /fix-nginx-404-on-refresh-spa-routing.html
5. Verification Steps
# Confirm Ingress has an ADDRESS
kubectl get ingress -n <namespace> -w
# Watch for ADDRESS to populate (may take 30-60s for cloud LBs)
# Test with curl using the Host header (before DNS is set up)
INGRESS_IP=$(kubectl get ingress my-ingress -n <namespace> -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl -H "Host: app.example.com" http://$INGRESS_IP/
# Test HTTPS
curl -k -H "Host: app.example.com" https://$INGRESS_IP/
# Check Ingress controller logs for your hostname
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=100 | grep "app.example.com"
6. Common Mistakes
- Creating an Ingress resource before installing an Ingress controller — the resource exists but nothing processes it
- Mismatching the ingressClassName between the Ingress spec and the installed IngressClass resource name
- Putting the TLS secret in a different namespace from the Ingress — TLS secrets must be in the same namespace
- Using
pathType: Exactfor paths that need prefix matching (e.g./apito match/api/users) - Checking the Ingress ADDRESS without checking if DNS resolves to it — an Ingress can have an IP but routing fails if DNS points elsewhere
- Not checking backend Service endpoints — the Ingress routes to a Service, but if the Service has no ready pods, all requests return 502
7. Prevention Tips
- Use
kubectl get ingress -wimmediately after applying to verify the ADDRESS populates within 60 seconds - Add Ingress smoke tests to your CI/CD pipeline —
curl -f http://your-host/healthafter deploy - For production, use cert-manager to automate TLS certificate provisioning and renewal
- Monitor Ingress controller logs for 4xx/5xx patterns with Prometheus metrics if your controller exposes them
- For AWS Load Balancer Controller, always verify IAM permissions and subnet tags before creating Ingress resources
- If DNS resolution inside the cluster is failing, pods may not be able to reach Services referenced in the Ingress, appearing as a routing failure
8. FAQ
The Ingress ADDRESS shows an IP but browsing to the hostname times out. Why?
The Ingress has been provisioned but DNS isn't pointing to it yet. Either your DNS record hasn't been updated to point to the Ingress IP/hostname, or DNS propagation hasn't completed. Test by hitting the Ingress IP directly with a Host header: curl -H "Host: app.example.com" http://<ingress-ip>/. If that works, the issue is DNS.
The Ingress gives 502 Bad Gateway. What does that mean?
The Ingress controller reached the backend Service but got an error. Check: (1) Service has ready endpoints (kubectl get endpoints), (2) pods are Running and 1/1 ready, (3) the Service port matches what the pods are listening on. A 502 means routing is working — the backend application is the issue.
How do I use the same Ingress for both HTTP and HTTPS?
Configure the tls block in the Ingress spec and add an annotation to redirect HTTP to HTTPS: for NGINX Ingress Controller use nginx.ingress.kubernetes.io/ssl-redirect: "true". For cert-manager TLS automation, add cert-manager.io/cluster-issuer annotation and cert-manager will provision the certificate and populate the TLS secret automatically.
9. Summary
| Symptom | Cause | Fix |
|---|---|---|
| Ingress ADDRESS is empty | Controller not running or wrong class | Check controller pods; verify ingressClassName matches |
| 502 Bad Gateway | Backend Service has no ready endpoints | Check Service selector and pod readiness |
| 404 on specific paths | Path type mismatch or wrong path spec | Use Prefix instead of Exact; check path ordering |
| HTTPS returns certificate error | TLS secret missing or wrong namespace | Check secret exists in same namespace as Ingress |
| Works with IP, not hostname | DNS not pointing to Ingress address | Update DNS A/CNAME record to Ingress IP or hostname |
Explore More in This Category
Explore more in this category: Kubernetes guides. Browse all DevOps Compass articles or jump to: Kubernetes, AWS, CI/CD, Containers, Monitoring, Networking.