HTTPS Redirect Best Practices: 301 vs 302 & Common Mistakes
Forcing HTTPS sounds simple: redirect every HTTP request to HTTPS. In practice, teams routinely choose the wrong redirect type, create redirect loops, misconfigure HSTS, or lose SEO equity in the process. This guide covers every scenario correctly.
Why Getting HTTPS Redirects Wrong Is Costly
An incorrect HTTPS redirect can:
- Destroy SEO equity by sending the wrong redirect code, causing search engines to not transfer PageRank to the canonical HTTPS URL
- Create redirect loops that make your site inaccessible, especially when a reverse proxy or CDN is in the chain
- Break API clients that do not follow redirects automatically
- Leave HSTS misconfigured, exposing users to downgrade attacks even after you have deployed TLS
- Fail WCAG and security audits that check for mixed content and improper redirect chains
The correct approach varies depending on your stack. This guide covers Nginx, Apache, Cloudflare, and application-level redirects with copy-paste configurations you can use immediately.
301 vs 302: Which One to Use
This is the most common point of confusion. Here is the definitive answer:
- 301 Moved Permanently - Use this for HTTP to HTTPS redirects. It tells browsers and search engines that the resource has permanently moved. Browsers cache 301 responses, so subsequent visits skip the redirect entirely. Search engines transfer link equity (PageRank) through 301 redirects.
- 302 Found (Temporary) - Use this only for genuinely temporary situations: A/B testing, maintenance pages, or feature flags where the original URL will return. Browsers do not cache 302 responses. Search engines do not transfer PageRank through 302 redirects in the same way.
- 307 Temporary Redirect - Like 302, but guarantees the HTTP method is preserved. Use this for temporary API redirects where you must not change POST to GET.
- 308 Permanent Redirect - Like 301, but guarantees the HTTP method is preserved. Useful for permanent API endpoint moves.
For HTTP to HTTPS: always use 301. There is no legitimate reason to use a 302 for this purpose, and doing so silently costs you SEO equity every day.
Nginx Configuration
The cleanest and most performant approach in Nginx is a dedicated server block for port 80 that returns a 301:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Add HSTS header
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Rest of your config...
}
The key detail is using $host rather than $server_name in the redirect target. $server_name always uses the first name in the server_name directive, which can cause issues if the request came in on a different hostname. $host preserves the original request hostname.
Avoid using rewrite ^(.*) https://... for HTTPS redirects - return 301 is faster because Nginx does not need to process regex.
Apache Configuration
In Apache, the preferred method is a VirtualHost-level redirect in your configuration file rather than .htaccess (which requires AllowOverride and has a performance overhead on every request):
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
If you must use .htaccess (shared hosting, or the server config is not accessible):
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Behind a load balancer or reverse proxy, the %{HTTPS} variable may always show as "off" because the proxy terminates SSL. In that case, check the X-Forwarded-Proto header instead:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Cloudflare Configuration
If your site is behind Cloudflare, you can enforce HTTPS at the Cloudflare layer without touching your origin server. Two approaches:
- Always Use HTTPS (recommended): In Cloudflare Dashboard → SSL/TLS → Edge Certificates, enable "Always Use HTTPS." Cloudflare will issue a 301 redirect for all HTTP requests before they reach your origin. This is the most efficient option because the redirect happens at the CDN edge.
- Page Rule (legacy): Create a Page Rule matching
http://*.example.com/*with the action "Always Use HTTPS." Page Rules are being phased out in favor of Rules.
Important: If you use Cloudflare's "Flexible" SSL mode, your origin still receives HTTP requests from Cloudflare. If your origin also redirects HTTP to HTTPS, this creates a redirect loop. Set Cloudflare SSL mode to "Full" or "Full (Strict)" to avoid this.
HSTS: The Layer Above Redirects
A 301 redirect stops browser requests from completing on HTTP, but the first request is still sent in plaintext. HSTS (HTTP Strict Transport Security) eliminates even that first plaintext request by instructing the browser to always use HTTPS for your domain for a specified period.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Breaking down the directives:
- max-age=31536000 - Browser should use HTTPS for the next 1 year (31,536,000 seconds). Start with a low value (300) while testing, then increase to 31536000 once confirmed working.
- includeSubDomains - Apply HSTS to all subdomains. Only add this if all your subdomains support HTTPS. A subdomain without HTTPS will become inaccessible for HSTS-compliant browsers.
- preload - Submit your domain to the HSTS preload list (hstspreload.org), which is baked into browsers. Preloaded domains never make an HTTP request, even on the first visit.
Warning: HSTS with
preloadis very difficult to undo. Once submitted, removal can take months to propagate. Only addpreloadif you are certain you will never need HTTP on this domain again.
Step-by-Step: Setting Up HTTPS Redirects Correctly
- Verify your SSL certificate is valid and covers all hostnames (apex domain and www). Use our SSL Checker to confirm.
- Configure your web server with a dedicated HTTP (port 80) server block or VirtualHost that does nothing except return a 301 redirect to the HTTPS equivalent URL.
- Test the redirect before adding HSTS:
curl -I http://example.com/should return301 Moved Permanentlywith aLocation: https://example.com/header. - Verify no redirect chain exists: The HTTP URL should redirect directly to the HTTPS URL in one hop. HTTP → HTTP/www → HTTPS is two hops and costs a round-trip.
- Add HSTS with a short max-age first: Deploy with
max-age=300(5 minutes) and test thoroughly. Once confirmed, increase tomax-age=31536000. - Add includeSubDomains only after verifying all subdomains have valid TLS.
- Submit to HSTS preload list as the final step, after the full
max-age=31536000; includeSubDomains; preloadheader has been live for a period.
Generate Your Nginx Config Instantly
Our free Nginx Config Generator produces production-ready server blocks with HTTPS redirects, SSL settings, HSTS headers, and security hardening - in seconds.
Open Nginx Config GeneratorCommon Mistakes and How to Avoid Them
Mistake 1: Redirect Loop When Behind a Proxy
This is the most common production issue. Your Apache or Nginx origin server sees every request as HTTP because the proxy terminates TLS. Your redirect rule fires unconditionally, sending a 301 to HTTPS. The proxy then requests the HTTPS version... which your origin again sees as HTTP. Infinite loop.
Fix: Check X-Forwarded-Proto or $http_x_forwarded_proto instead of $scheme or %{HTTPS}. Trust only proxies you control.
Mistake 2: Redirecting www to non-www (or vice versa) Separately from HTTPS
If you need both an HTTP-to-HTTPS redirect and a www-to-apex redirect, combine them into a single 301 per URL. Two sequential redirects (HTTP→HTTPS, then www→apex) add latency and are suboptimal for SEO.
# Nginx: combine both in one rule
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
Mistake 3: Mixed Content After HTTPS Migration
Even after redirecting to HTTPS, pages can include HTTP resources (images, scripts, stylesheets). These "mixed content" resources trigger browser warnings and may be blocked entirely in modern browsers. Audit with browser DevTools (Console tab) or a tool like curl on your HTML output searching for http:// in resource URLs.
Mistake 4: HSTS on a Domain That Is Not Ready
Adding HSTS with a long max-age before your site fully supports HTTPS means users with a cached HSTS header cannot reach your site at all if your certificate expires or you need to temporarily serve HTTP. Always test with a short max-age first.
Frequently Asked Questions
Does an HTTPS redirect hurt my page speed scores?
A 301 redirect adds one round-trip for first-time visitors. This is typically 20-100ms depending on network conditions. Browsers cache 301 redirects, so repeat visitors experience no redirect overhead. Google's Core Web Vitals measure LCP, FID, and CLS - the redirect adds to TTFB but is usually not the primary bottleneck. The SEO and security benefits of HTTPS far outweigh this minor latency cost.
Should I redirect at the CDN layer or the origin?
CDN layer is preferred when available. Cloudflare, Fastly, and similar CDNs can redirect HTTP to HTTPS at their edge nodes globally, eliminating a round-trip to your origin. This is faster and reduces origin server load. Use origin-level redirects only as a fallback or if you do not have a CDN.
What happens if I set HSTS and my certificate expires?
Users with a cached HSTS policy for your domain will see a connection error they cannot bypass (no "proceed anyway" option). This is by design - it prevents downgrade attacks. The practical consequence is that certificate renewal becomes critical. Automate certificate renewal with Let's Encrypt / Certbot or equivalent, and set up monitoring to alert before expiry.
Do I need to redirect both http://example.com and http://www.example.com?
Yes. Both HTTP variants should redirect to your canonical HTTPS URL. If your canonical is https://example.com (no www), then http://example.com, http://www.example.com, and https://www.example.com should all 301 to https://example.com.
Can I use meta refresh for HTTPS redirects?
No. Meta refresh (<meta http-equiv="refresh" content="0;url=https://...">) is not a true HTTP redirect. It requires the browser to download the full HTTP page first, then navigate. Search engines do not follow meta refreshes the same way as 301 redirects. It also does not work for non-HTML resources. Never use meta refresh for HTTPS migration.
Use our free tool here → Nginx Config Generator
Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.