The Problem

When a page is loaded over HTTPS, browsers block any resources (images, scripts, stylesheets, iframes) loaded over HTTP. This is called "mixed content" and is a security risk.

Symptoms

  • Console error: "Mixed Content: The page was loaded over HTTPS but requested an insecure resource"
  • Images, fonts, or scripts do not load on production
  • Page looks broken on HTTPS but works on HTTP
  • Works in development (HTTP) but not production (HTTPS)

Real Error Message

bash
Mixed Content: The page at 'https://example.com/' was loaded over HTTPS,
but requested an insecure image 'http://cdn.example.com/image.jpg'.
This request has been blocked; the content must be served over HTTPS.

Types of Mixed Content

  • Passive (images, audio, video): Browser shows warning, may block
  • Active (scripts, styles, iframes): Browser ALWAYS blocks

How to Fix It

Fix 1: Use Protocol-Relative URLs

html
<!-- Instead of http:// or https:// -->
<img src="//cdn.example.com/image.jpg">
<script src="//cdn.example.com/lib.js"></script>

Note: This is considered legacy. Prefer explicit HTTPS.

Fix 2: Use Explicit HTTPS URLs

html
<img src="https://cdn.example.com/image.jpg">
<link href="https://fonts.googleapis.com/css2?family=Roboto" rel="stylesheet">

Fix 3: Upgrade-Insecure-Requests Header

nginx
# nginx.conf - automatically upgrade HTTP to HTTPS
add_header Content-Security-Policy "upgrade-insecure-requests" always;
html
<!-- Or via meta tag -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

Fix 4: Find and Fix Hardcoded HTTP URLs

```bash # Search your codebase for http:// grep -r "http://" src/ --include="*.html" --include="*.js" --include="*.css"

# Check database content for HTTP URLs SELECT * FROM posts WHERE content LIKE '%http://%'; ```

Fix 5: Handle Dynamic Content URLs

```javascript // If URLs come from a CMS or API, ensure they use HTTPS function ensureHttps(url) { return url.replace(/^http:///i, 'https://'); }

<img src={ensureHttps(user.avatarUrl)} alt="Avatar"> ```

Fix 6: Debug with Browser DevTools

  1. 1.Open Chrome DevTools Security tab
  2. 2.Click "View certificate" to verify HTTPS
  3. 3.Check the Security panel for mixed content warnings
  4. 4.Use the Console to see all blocked resources