What the message looks like
Mixed Content: The page at 'https://example.com/' was loaded over HTTPS, but requested an insecure script 'http://example.com/js/app.js'. This request has been blocked; the content must be served over HTTPS.Common causes
- Hard-coded
http://URLs in templates, CSS, JavaScript or in the content stored in the database. - The site moved to HTTPS but the CMS still has
http://insiteurl,homeor in old posts. - Behind a reverse proxy the application does not know the request was HTTPS and generates
http://links (missingX-Forwarded-Proto). - A third-party script, font or widget is loaded over HTTP.
- A redirect inside the application sends an API or asset request to an
http://address.
Check
- List http:// resources in the delivered HTML
curl -s https://example.com/ | grep -oE '(src|href|action)="http://[^"]+"' | sort -u | head -n 20 - Is a policy that upgrades requests already set?
curl -sI https://example.com/ | grep -i 'content-security-policy' - Does the proxy pass the scheme to the app?
nginx -T 2>/dev/null | grep -n 'X-Forwarded-Proto' - The exact blocked URLs
curl -s https://example.com/assets/app.css | grep -oE 'url\(http://[^)]+\)' | sort -u
Fix
- Replace
http://withhttps://(or a relative URL such as/js/app.js) in templates, CSS and JavaScript. - Update the CMS: set the site address to
https://and run its search-and-replace for old content in the database, with a backup first. - Pass the scheme behind a proxy:
proxy_set_header X-Forwarded-Proto $scheme;, and tell the application to trust it. - As a stopgap, send
Content-Security-Policy: upgrade-insecure-requestsso the browser upgrades requests that the server supports over HTTPS. - Replace third-party resources that have no HTTPS version.
FAQ
Why are some mixed resources only warned and others blocked?
Browsers treat scripts, styles and requests (active content) as blocked, and images, audio and video (passive content) more leniently, or upgrade them. Rely on neither: fix all of them.
Is upgrade-insecure-requests a real fix?
It works only when the target also exists on HTTPS. It is a good safety net, but the URLs should still be corrected at the source.