An HTTP-to-HTTPS redirect is a server response that tells the browser the requested resource has permanently moved to the HTTPS version of the same URL. The standard implementation is a 301 (Moved Permanently) status code with a Location header pointing to https://. After serving HTTPS, you add the Strict-Transport-Security (HSTS) header so browsers stop attempting plain HTTP altogether.
This is the complement to enabling HTTPS — see why your website must use HTTPS. Without redirects, search engines index two versions of your site, users on old links transmit data in the clear, and you remain exposed to SSL-stripping attacks.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload.http://example.com/page directly to https://example.com/page, not via http://www.example.com.| Platform | Where | Method |
|---|---|---|
| Apache | .htaccess or vhost | mod_rewrite or Redirect |
| Nginx | server block | return 301 |
| IIS (Windows) | web.config | URL Rewrite module |
| Next.js | next.config.js | redirects() |
| Edge runtime / managed host | Automatic | Built-in HTTPS enforcement |
| CDN dashboard | Edge setting | SSL/TLS → Always Use HTTPS |
| CDN distribution | Distribution behavior | Viewer Protocol Policy |
# .htaccess — redirect all HTTP to HTTPS, preserve path and query
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Add HSTS on the HTTPS response
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</IfModule># Catch all HTTP traffic and 301 to HTTPS
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, ssl_certificate_key ...
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}<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>Hosted on a managed edge runtime? HTTPS redirects happen automatically — you do not need this. For self-hosted Next.js behind a reverse proxy without HTTPS handling, use the headers() hook to add HSTS and let the upstream server do the 301.
// next.config.js — add HSTS to every response
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
],
},
];
},
};Easiest path. In your CDN dashboard, find the SSL/TLS or edge-certificates section and toggle Always Use HTTPS on. The CDN will issue a 301 at the edge for any HTTP request before it reaches your origin. Enable HSTS in the same screen and tick Include subdomains + Preload once you have verified everything works.
A 301 redirect alone leaves a window: an attacker on the network can intercept the very first plain-HTTP request and serve a fake response. HSTS instructs the browser to refuse plain HTTP for a domain for the duration of max-age. Adding the preload directive and submitting to hstspreload.org bakes your domain into Chrome, Firefox, Safari, and Edge source code so the first visit is also protected.
Requirements for preloading: serve a valid HTTPS cert, redirect HTTP to HTTPS on the same host, send HSTS with max-age at least 31536000 (1 year), includeSubDomains, and preload.
# Bad — 302 is temporary; search engines may keep indexing HTTP
return 302 https://$host$request_uri;
# Good — 301 is permanent
return 301 https://$host$request_uri;Each hop adds latency and dilutes link equity. Redirect once, directly to the final URL.
window.location = 'https://...' runs only after the insecure page has already loaded — too late. Always redirect at the server or edge.
Redirecting example.com but not blog.example.com leaves part of the site insecure. Cover every subdomain you serve.
Once a browser sees HSTS with a long max-age, it refuses HTTP for that period. If your HTTPS breaks, users are locked out. Start with max-age=300, verify, then raise to a year and add preload.
301 Moved Permanently with a Location: https://... header.301 (permanent) transfers SEO authority and is cached aggressively by browsers. 302 (temporary) tells search engines to keep indexing the original URL.
Yes. Redirects work, but every internal link that still points at HTTP costs a redirect hop. Search-and-replace the database/codebase to use absolute HTTPS URLs or protocol-relative paths.
Done correctly with 301s, the change is transparent. Submit the new HTTPS property in Google Search Console and update the canonical URLs.
Yes for the redirect. You should still set HSTS on the origin so the policy persists if the CDN is ever bypassed.
Yes — directly. AI crawlers (GPTBot, ChatGPT-User, PerplexityBot, ClaudeBot) treat insecure HTTP responses with caution and frequently skip them in favor of HTTPS sources. If your HTTP-to-HTTPS redirect is broken or returns mixed-protocol content, AI Overviews and chat assistants are far less likely to cite your pages, since the citation chain has to be reliable end-to-end. A clean 301 plus HSTS gives AI crawlers a single canonical HTTPS URL to fetch, index, and quote.
An attacker on the same network intercepts a victim's plain-HTTP request and proxies it to your HTTPS site, while serving the victim a forged HTTP page. HSTS preload eliminates this attack.
Either is fine — pick one and be consistent. Make sure both are covered by your certificate so a misdirected user does not hit a cert warning.
A correct HTTP-to-HTTPS migration is three things: a 301 redirect at the server or edge, an HSTS header with a long max-age, and submission to the preload list. With those in place, every visitor — including the ones following five-year-old links — reaches your site over an authenticated, encrypted connection. Run a Greadme deep scan to verify your HTTPS redirect works on every URL across your site and to catch any pages still serving plain HTTP.