HTTP to HTTPS Redirects: The Complete Guide
Complete guide to migrating from HTTP to HTTPS: server configuration, redirect implementation, mixed content issues, HSTS, and SEO considerations for a smooth transition.
Migrating from HTTP to HTTPS is one of the most common redirect operations, and one of the easiest to get wrong. A correct implementation is a single 301 redirect per URL. A botched implementation creates redirect loops, mixed content warnings, SEO ranking drops, and broken functionality.
This guide covers every step of the HTTP to HTTPS migration: server configuration, redirect rules, mixed content resolution, HSTS deployment, and SEO verification.
Why HTTPS Matters
HTTPS is no longer optional. It is a baseline requirement for any website.
Security
SEO ranking signal
Browser trust
Required for modern APIs
HTTP/2 and HTTP/3
The Redirect Architecture
The correct HTTP to HTTPS redirect is a 301 from every HTTP URL to its HTTPS equivalent:
http://example.com/any-page
--> 301 --> https://example.com/any-page
http://www.example.com/any-page
--> 301 --> https://www.example.com/any-page
The redirect should preserve the full path and query string. It should not redirect to the homepage or strip URL parameters.
CORRECT:
http://example.com/products?category=shoes&sort=price
--> https://example.com/products?category=shoes&sort=price
WRONG:
http://example.com/products?category=shoes&sort=price
--> https://example.com/ (path and query lost)
--> https://example.com/products (query string lost)
Server Configuration
Nginx
# Redirect all HTTP traffic to HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# HTTPS server block
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# ... your site configuration
}
Use return, not rewrite
In Nginx, return 301 is faster than rewrite ... permanent because it does not require regex processing. For a simple HTTP-to-HTTPS redirect, always use return.
Apache
# In .htaccess or VirtualHost config
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Apache (alternative with mod_alias)
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
IIS (web.config)
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="HTTP to HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
CDN-Level Redirects
Most CDNs offer HTTPS enforcement at the edge, which is the fastest option:
| CDN | Setting | Location |
|---|---|---|
| Cloudflare | Always Use HTTPS | SSL/TLS > Edge Certificates |
| AWS CloudFront | Viewer Protocol Policy: Redirect HTTP to HTTPS | Distribution > Behaviors |
| Fastly | Force TLS and HSTS | Configuration > Settings |
| Vercel | Automatic (enabled by default) | No configuration needed |
| Netlify | Automatic (enabled by default) | Domain settings > HTTPS |
Trace your redirect chains
Find redirect loops, broken chains, and unnecessary hops instantly.
Avoiding Redirect Loops
The most common HTTP-to-HTTPS redirect problem is a loop. It happens when your application or origin server does not know the request originally arrived over HTTPS because a load balancer or CDN terminated the SSL connection.
User (HTTPS) --> CDN/LB (terminates SSL) --> Origin (sees HTTP)
Origin: "This is HTTP, redirect to HTTPS"
CDN/LB: follows redirect, terminates SSL again
Origin: "This is still HTTP, redirect to HTTPS"
... (loop)
The Fix: Trust X-Forwarded-Proto
When a load balancer terminates SSL, it adds an X-Forwarded-Proto: https header. Your redirect rule should check this header:
# Nginx behind a load balancer
server {
listen 80;
# Only redirect if the original request was HTTP
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
}
# Apache behind a load balancer
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Do not redirect at multiple layers
Configure the HTTP-to-HTTPS redirect at exactly one layer: either the CDN, the load balancer, or the web server. Never at more than one. Multiple redirect layers working independently is the most common cause of HTTPS redirect loops.
Mixed Content: The Hidden Problem
After enabling HTTPS, your pages may still load resources (images, scripts, stylesheets, fonts) over HTTP. Browsers block or warn about this "mixed content."
Types of Mixed Content
| Type | Examples | Browser Behavior |
|---|---|---|
| Active (blocked) | Scripts, stylesheets, iframes, fetch/XHR | Blocked entirely, page may break |
| Passive (warning) | Images, video, audio | Loaded with warning in console |
Finding Mixed Content
Check your browser's DevTools console for mixed content warnings:
Mixed Content: The page at 'https://example.com/page' was loaded over HTTPS,
but requested an insecure image 'http://example.com/image.jpg'.
Fixing Mixed Content
Update internal references to protocol-relative or HTTPS
Change http://example.com/image.jpg to https://example.com/image.jpg or //example.com/image.jpg (protocol-relative).
Update hardcoded HTTP URLs in your database
For CMS sites, run a search-and-replace on your database to update http://yourdomain.com to https://yourdomain.com.
Update third-party resource URLs
Ensure all external scripts, stylesheets, and images use HTTPS. Most third-party services support HTTPS.
Add Content-Security-Policy header
Use upgrade-insecure-requests to automatically upgrade HTTP requests to HTTPS:
Content-Security-Policy: upgrade-insecure-requests
HSTS: Making HTTPS Permanent
HTTP Strict Transport Security (HSTS) tells browsers to always use HTTPS for your domain, even if the user types http://. This eliminates the initial HTTP request entirely after the first visit.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
HSTS Deployment Strategy
Deploy HSTS gradually to avoid locking yourself out:
Start with a short max-age
Set max-age=300 (5 minutes). If something breaks, it only lasts 5 minutes.
Increase gradually
After confirming everything works, increase to max-age=86400 (1 day), then max-age=604800 (1 week).
Set final max-age
Once confident, set max-age=31536000 (1 year) and add includeSubDomains.
Submit to HSTS preload list (optional)
Add the preload directive and submit your domain to hstspreload.org. This hardcodes HTTPS enforcement into browsers. Be absolutely certain before doing this, as removal takes months.
HSTS preload is hard to undo
Once your domain is on the HSTS preload list, every Chrome, Firefox, Safari, and Edge user will be forced to use HTTPS. Removing your domain from the list takes months and requires a browser update to take effect. Only preload after you are 100% committed to HTTPS on all subdomains.
SEO Checklist for HTTP to HTTPS
After implementing the redirect, verify these SEO elements:
- Google Search Console: Add the HTTPS property and verify ownership. The HTTP and HTTPS versions are separate properties.
- Sitemap: Update your sitemap to use HTTPS URLs. Submit the updated sitemap in Search Console.
- Canonical tags: Ensure all
<link rel="canonical">tags use HTTPS URLs. - Internal links: Update all internal links from HTTP to HTTPS. While the redirect handles them, direct HTTPS links are faster and avoid redirect hops.
- Robots.txt: Ensure the HTTPS version of robots.txt is accessible and correct.
- Structured data: Update any absolute URLs in your JSON-LD or schema markup to HTTPS.
- Social meta tags: Update Open Graph and Twitter Card URLs to HTTPS.
Verification
After deployment, verify the complete redirect chain:
# Check the redirect
curl -I http://example.com/
# Should show: HTTP/1.1 301 Moved Permanently
# Location: https://example.com/
# Check HSTS header
curl -I https://example.com/
# Should show: Strict-Transport-Security: max-age=31536000; ...
# Check for mixed content (download page and search for http://)
curl -s https://example.com/ | grep -c "http://"
# Should be 0 (or only in safe contexts like links to external sites)
For a full site audit, use a redirect tracing tool that can check every URL for correct HTTPS enforcement, proper status codes, and mixed content issues.
Related Articles
HTTPS migration is a one-time cost that pays for itself forever. Get the redirect right on day one.
Never miss a broken redirect
Trace redirect chains and detect issues before they affect your users and SEO. Free instant tracing.