How to redirect every version of your site to one HTTPS address
Your domain can be typed four ways: http://example.com, http://www.example.com, https://example.com and https://www.example.com. Every one of them should end up at the same HTTPS address, with a valid certificate, through a single permanent redirect. When one does not, visitors see a browser security warning or an insecure page, and search engines have to guess which copy is the real one, and may pick the one you did not want.
Test all four
curl -sI http://example.com
curl -sI http://www.example.com
curl -sI https://example.com
curl -sI https://www.example.com
Each http version should answer 301 or 308 with a Location on your HTTPS address, and each https version should either load (200) or redirect to the one that does. Use the command line or an online redirect checker rather than a browser: Chrome now upgrades http to https on its own, which hides a missing redirect. A certificate error from curl usually means that name is not covered by the certificate; an expired, self-signed or incompletely installed certificate causes the same error.
Pick one address
Choose either www.example.com or example.com as the version of your site. Either works; Google's advice is to pick one and redirect the others. What matters is using the same one everywhere: in the redirects below, your canonical tags, your sitemap and your Search Console property. If the site is established, keep whichever version is already indexed.
Make sure the certificate covers both names
The HTTPS certificate has to list both example.com and www.example.com, or whichever name it misses will show a security warning before the redirect can run. Most hosts (Cloudflare, Netlify, Vercel, Squarespace, Shopify, Wix and most managed WordPress hosts) issue and renew certificates automatically, but only for names they know about.
- Add both names as domains in your host's dashboard, and set the one you picked as primary.
- Point both names at the host in DNS. A
wwwrecord left pointing at an old server is a common reason one version fails.
Add the redirects
Cloudflare (any site behind it)
- Under SSL/TLS → Overview, set the encryption mode to Full (strict) if your origin has a valid certificate from a public certificate authority or a Cloudflare Origin CA certificate (a self-signed one fails in this mode with error 526). If the page shows Automatic SSL/TLS, Cloudflare picks the mode for you; choose Custom SSL/TLS to set it yourself.
- Under SSL/TLS → Edge Certificates, turn on Always Use HTTPS. This redirects every http request to https.
- Under Rules → Overview, create a redirect rule from the version you are not using to the one you are. The Redirect from WWW to Root template is a good start, but it only matches https, so
http://www.example.comwould take two hops. Change the request URL tohttp*://www.example.com/*and the target URL tohttps://example.com/${2}(swap the names if you picked www). Keep status 301 and Preserve query string on.
Then test all four versions with curl and check each reaches your address in one hop.
Netlify and Vercel
Both serve HTTPS automatically and redirect http to https. Add both the root and www names to the project, then mark the one you picked as primary (Netlify) or set the other to redirect to it (Vercel: Settings → Domains, edit the domain and choose Redirect to with a 301 or 308 status). On Vercel, http://www.example.com goes to https://www.example.com first and then to your chosen name; Vercel does not let you change that, so expect a two-hop warning for that one version.
Apache (.htaccess)
This sends every request that is not already https://example.com there in one hop. Swap the host name for www.example.com if that is your version, and adjust the second condition to match the other name.
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]
If the site sits behind a CDN or load balancer that handles HTTPS, Apache may see every request as plain http and loop. In that case test %{HTTP:X-Forwarded-Proto} instead of %{HTTPS}, or do the redirect at the CDN.
Nginx
Add these two blocks alongside your existing HTTPS server block for example.com. The second needs a certificate that covers www.example.com; point the two ssl_certificate lines at your own files.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name www.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
return 301 https://example.com$request_uri;
}
WordPress
Under Settings → General, set both WordPress Address and Site Address to your HTTPS address. Then do the redirect at the server or host: many managed WordPress hosts have a setting for this, often called Force HTTPS. Avoid adding a redirect plugin on top of a host redirect; stacked rules are how redirect chains happen.
Avoid redirect chains
Each version should reach the final address in one hop. http://www.example.com → https://www.example.com → https://example.com works, but it is two redirects where one would do, and every hop adds a round trip for visitors and crawlers. Use permanent redirects (301 or 308). A temporary 302 or 307 tells search engines to keep the old address indexed.
Fix mixed content
Mixed content is an HTTPS page that loads an image, script or stylesheet over http://. Browsers block insecure scripts and styles outright and may block or flag insecure images, so parts of the page break or the padlock disappears.
- Find it. Open the browser's developer tools on the Console tab and load the page. Each insecure request is listed.
- Fix it at the source. Change the
http://address tohttps://in your theme, template or content. In WordPress, old post content is the usual culprit: a search-and-replace tool (for examplewp search-replace 'http://example.com' 'https://example.com' --skip-columns=guidwith WP-CLI; run it with--dry-runfirst to preview) fixes it in one pass. Leave theguidcolumn alone: changing it makes feed readers show old posts as new. Back up the database first. - Use a stopgap if you must. The
Content-Security-Policy: upgrade-insecure-requestsheader tells browsers to fetch those resources over HTTPS instead. It only works if each resource is actually available over HTTPS.
Then turn on HSTS
Once every version redirects correctly, add the Strict-Transport-Security header so browsers go straight to HTTPS on later visits without asking over http first. The security headers guide covers the value to use and when to consider preloading.
Check it worked
Run WEBCHKR again. The HTTPS/SSL check tries all four versions of the address you enter. It passes when every https version completes a secure connection and every http version redirects to HTTPS on your own site; it warns when a version does not redirect, cannot connect, or takes more than one hop; and it fails when HTTPS does not work at all or redirects back to http. Each version is listed with what happened, so you can see which one to fix. It does not check that all four end on the same address or that the redirects are permanent, so confirm those with the curl commands above. If you check a subdomain such as shop.example.com, the www version tried is www.shop.example.com, and a warning about it is expected if that name does not exist. Mixed content is reported as a note on the same card.