← Back to list

The Hidden HTTPS Bug Behind Load Balancers

The subtle HTTPS bug behind mixed content errors, broken redirects, and failed OAuth flows.

Samir Patil · 2026-05-24 19:56 · 0 claps · 1.9 min read
#cloud-infrastructure #design-systems #software-engineering
Open on Medium ↗
Wiki topics: PRD · Product Design

Why Your App Breaks Behind a Load Balancer

You deploy your app.

HTTPS is enabled. The SSL certificate works. Everything looks perfect.

Then suddenly:

“Mixed Content: The page at ‘https://yourdomain.com' was loaded over HTTPS, but requested an insecure resource ‘http://yourdomain.com/api/...' This request has been blocked.”

Or you get a redirect loop. Or your API calls silently fail.

You check your load balancer — HTTPS is configured correctly. You check Nginx — it’s running. You check your backend — it’s healthy.

So what went wrong?

The issue usually isn’t your load balancer. It isn’t Nginx either.

Your backend simply doesn’t know the original request was HTTPS.

The Architecture Most Apps Use

Browser → HTTPS → Load Balancer
                     ↓ HTTP
                  Nginx / Proxy
                     ↓ HTTP
                   Backend

This setup is called SSL termination.

The load balancer handles HTTPS, while internal traffic stays on HTTP inside a private network.

This is completely normal in production.

Why Mixed Content Happens

Your browser sends:

https://yourapp.com

The load balancer forwards it internally as HTTP.

Now your backend thinks:

"This is an HTTP request"

So when it generates redirects or absolute URLs, it returns:

http://yourapp.com/login

The browser blocks it because the original page was loaded over HTTPS.

That’s the entire bug.

The Wrong Fix

Many engineers solve this by enabling HTTPS everywhere internally too:

Browser → HTTPS → Load Balancer → HTTPS → Nginx

It works.

But now you manage certificates in two places and add unnecessary TLS overhead internally.

You fixed the symptom, not the root cause.

The Real Fix: X-Forwarded-Proto

Load balancers send a header like this:

X-Forwarded-Proto: https

This tells your backend:

“The original client request was HTTPS.”

Nginx

proxy_set_header X-Forwarded-Proto $scheme;

Express / NestJS

app.set('trust proxy', 1)

Django

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

FastAPI

Enable trusted proxy headers so redirects and generated URLs use HTTPS correctly.

Final Architecture

Browser (HTTPS)
      ↓
Load Balancer
      ↓
X-Forwarded-Proto: https
      ↓
Nginx
      ↓
Backend

Now your backend correctly generates:

https://yourapp.com

No mixed content. No redirect loops. No duplicate TLS setup.

TL;DR

SSL termination at the load balancer is the correct production setup.

Mixed content errors happen because your backend thinks requests are HTTP.

The proper fix is:

  • pass X-Forwarded-Proto
  • trust proxy headers in your framework
  • let the backend know the original request was HTTPS

One header. One configuration. Problem solved.


메타데이터
post_id
32abdce08231
slug
the-hidden-https-bug-behind-load-balancers-32abdce08231
url
https://medium.com/@samir00/the-hidden-https-bug-behind-load-balancers-32abdce08231
canonical_url
https://medium.com/@samir00/the-hidden-https-bug-behind-load-balancers-32abdce08231
author_url
https://medium.com/@samir00
status
ok
fetched_at
2026-06-09 15:37:30