šŸŽ‰ DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Nginx Ingress SSL Redirect Loop — Fix

Your site hits an infinite redirect loop after adding TLS to Nginx Ingress. Here's every reason it happens and exactly how to fix each one.

DevOpsBoysJun 10, 20263 min read
Share:Tweet

You add TLS to your Nginx Ingress, and suddenly your browser shows "This page isn't working — redirected you too many times." Classic redirect loop. Here's how to fix it.


What's Happening

The loop looks like this:

Browser → HTTP → Nginx Ingress redirects to HTTPS
Browser → HTTPS → app receives request
App thinks it's HTTP → redirects back to HTTPS
→ loop

Nginx terminates TLS and forwards plain HTTP to your backend. If your app (or another proxy in the chain) also tries to enforce HTTPS, it sees HTTP and redirects — creating an infinite loop.


Case 1: App Behind a Reverse Proxy Not Trusting X-Forwarded-Proto

The most common cause. Nginx sends X-Forwarded-Proto: https to tell the backend the original request was HTTPS. If your app ignores this header and checks the actual protocol (which is HTTP), it redirects.

Fix — add these annotations to your Ingress:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    nginx.ingress.kubernetes.io/proxy-set-headers: "ingress-nginx/custom-headers"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    # Tell upstream app the original scheme:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app
            port:
              number: 80

Fix in your app: Trust the X-Forwarded-Proto header.

For Django:

python
# settings.py
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

For Express.js:

javascript
app.set('trust proxy', 1);

For Rails:

ruby
# config/environments/production.rb
config.force_ssl = false  # Let Nginx handle redirect, not Rails

Case 2: ssl-redirect Annotation Causing Double Redirect

If your Ingress has ssl-redirect: "true" AND your app also redirects HTTP to HTTPS, you get a loop.

yaml
# Remove this if your app handles it, or disable app-level redirect:
annotations:
  nginx.ingress.kubernetes.io/ssl-redirect: "false"
  # Handle redirect only at Nginx level OR app level, not both

Case 3: Another Ingress or Load Balancer in Front

If you have AWS ALB → Nginx Ingress → App, the ALB terminates TLS and sends HTTP to Nginx. Nginx sees HTTP and redirects to HTTPS → ALB sees HTTPS and forwards HTTP to Nginx → loop.

Fix: disable ssl-redirect on Nginx when ALB handles TLS:

yaml
annotations:
  nginx.ingress.kubernetes.io/ssl-redirect: "false"
  nginx.ingress.kubernetes.io/use-forwarded-headers: "true"

Or configure ALB to forward the X-Forwarded-Proto header and tell Nginx to trust it:

yaml
annotations:
  nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
  nginx.ingress.kubernetes.io/compute-full-forwarded-for: "true"

Case 4: cert-manager Certificate Not Ready Yet

If you're using cert-manager and the certificate isn't issued yet, Nginx may serve the default self-signed cert. Some browsers redirect HTTP to HTTPS, hit the invalid cert, and loop.

bash
# Check certificate status
kubectl get certificate -n my-namespace
kubectl describe certificate myapp-tls -n my-namespace
 
# Check cert-manager logs
kubectl logs -n cert-manager deployment/cert-manager | tail -30

Wait for READY: True before testing.


Debug Flow

bash
# 1. Test with curl to see redirect chain
curl -Lv http://myapp.example.com 2>&1 | grep -E "Location|HTTP/"
 
# 2. Check what Nginx is actually sending to backend
kubectl logs -n ingress-nginx \
  $(kubectl get pod -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx -o name | head -1) \
  | grep myapp | tail -20
 
# 3. Check if X-Forwarded-Proto is being set
kubectl exec -it <your-pod> -- env | grep FORWARDED

If curl -Lv shows the same redirect repeating → loop confirmed. Check which hop is causing it — Nginx or your app.

Learn Kubernetes networking and Ingress setup at KodeKloud.

šŸ”§

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments