šŸŽ‰ 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.

DevOpsBoys3 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