Docs
Redirect HTTP to HTTPS
Redirect HTTP to HTTPS
Visitors rarely type https://. They type example.com, click an old link or open a bookmark from years ago, and the browser starts with http://. If the server answers that request with the page itself, the visit runs unencrypted: passwords, form data and cookies travel in plain text, and the browser marks the page Not secure. Google also sees two copies of every page, one on each protocol.
The fix is one permanent redirect: every http:// address answers with 301 (or 308) and points to the same address on https://. The site checklist treats a missing redirect as critical.
What the checklist expects
Answer on http:// |
Result |
|---|---|
301 or 308 to https://… |
OK |
302, 303 or 307 to https://… |
warning: the redirect is temporary, so search engines keep the http:// address |
200 with the page, or a redirect elsewhere |
fail: the site is served without encryption |
| port 80 closed | info: http:// does not open at all, so nothing leaks, but visitors who type the bare address get an error |
The redirect should go straight to the final address. http://example.com → https://example.com/ is one hop. A chain like http://example.com → http://www.example.com → https://www.example.com wastes time on every first visit (see One address, with or without www).
Check it yourself
Replace example.com with your site:
curl -sI http://example.com | grep -iE '^(HTTP|location)'
curl -sI http://example.com/some/page?x=1 | grep -iE '^(HTTP|location)'
Fixed looks like this, with the path and query kept in the second case:
HTTP/1.1 301 Moved Permanently
Location: https://example.com/
If the first line says 200, there is no redirect. If it says 302 or 307, the redirect is temporary.
How to fix
You need a valid certificate on https:// first; redirecting to a broken certificate locks every visitor out. Then pick what you have access to. Set the redirect in one place only: two layers that each redirect (for example Cloudflare and .htaccess) are where loops come from.
WordPress
- In Settings → General, set both WordPress Address (URL) and Site Address (URL) to
https://example.com. Log in again afterwards. - WordPress itself does not redirect
http://tohttps://. Add the redirect at the hosting level (cPanel, Plesk or.htaccesstab) or with the free Really Simple SSL plugin (now called Really Simple Security): after activating it, turn on SSL and enable its redirect. Where it offers a.htaccess301 redirect, prefer that over the PHP redirect: it is faster and also covers images and files. - Clear the page cache (WP Rocket, LiteSpeed Cache, your host's cache).
If the two URL fields are greyed out, they are set in wp-config.php (WP_HOME and WP_SITEURL); change them there.
cPanel
- Make sure the domain has a certificate: Security → SSL/TLS Status should show it as covered (AutoSSL issues one for free on most hosts).
- Open Domains → Domains.
- Turn on Force HTTPS Redirect next to the domain.
If the toggle is missing or greyed out, add the rule from the Apache tab to the .htaccess in the site's root (File Manager, with Show Hidden Files on).
Plesk
- Under Websites & Domains → example.com → SSL/TLS Certificates, make sure a valid certificate is installed (Let's Encrypt is free).
- Open Websites & Domains → example.com → Hosting & DNS → Hosting (Hosting Settings in older Plesk versions).
- Under Security, check that SSL/TLS support is on and the certificate is selected, then turn on Permanent SEO-safe 301 redirect from HTTP to HTTPS.
- Click OK (or Apply).
DirectAdmin
- Make sure the domain has a certificate: Account Manager → SSL Certificates (Let's Encrypt is free).
- Open Account Manager → Domain Setup and click the domain.
- Turn on Force SSL with https redirect and save.
nginx
Give port 80 its own server block that does nothing but redirect. It lives in your site's file: /etc/nginx/sites-available/example.com on Debian and Ubuntu, /etc/nginx/conf.d/example.com.conf on Rocky, Alma and CentOS.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
Write your main address in the return line (with or without www), so both variants reach it in one hop. Remove any root, location or PHP settings from this block: on port 80 it should not serve anything.
sudo nginx -t && sudo systemctl reload nginx
If you use Certbot, sudo certbot --nginx --redirect -d example.com -d www.example.com adds an equivalent block for you.
Apache and LiteSpeed
With server access (Apache). In the port 80 virtual host (/etc/apache2/sites-available/example.com.conf on Debian and Ubuntu, a file in /etc/httpd/conf.d/ on Rocky, Alma and CentOS):
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
sudo apachectl configtest && sudo systemctl reload apache2
(httpd instead of apache2 on Rocky, Alma and CentOS.)
Without server access (shared hosting, LiteSpeed). Put this at the top of the .htaccess in the site's root, above the # BEGIN WordPress block if there is one:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
The X-Forwarded-Proto line stops a loop when a proxy or CDN in front of the server already speaks HTTPS to the visitor and plain HTTP to your server.
Cloudflare
- Open the domain and go to SSL/TLS → Overview. Set the encryption mode to Full (strict) (your server needs a valid certificate; a free Cloudflare Origin Certificate works too).
- Go to SSL/TLS → Edge Certificates and turn on Always Use HTTPS. Cloudflare answers every
http://request with a301tohttps://.
Warning: Do not combine the Flexible mode with a redirect on your server. In Flexible mode Cloudflare talks to your server over plain HTTP, your server redirects to HTTPS, Cloudflare asks again over HTTP, and the browser stops with too many redirects. Use Full (strict), or leave the redirect to Cloudflare alone.
IIS and ASP.NET
Install the URL Rewrite module for IIS, then add this rule to the site's web.config:
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="HTTP to HTTPS" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTPS}" pattern="^OFF$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
redirectType="Permanent" sends a 301. The site also needs an http binding on port 80, or the request never reaches the rule.
In ASP.NET Core, app.UseHttpsRedirection() redirects with a temporary 307 by default. Make it permanent:
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
});
Hosted platforms
Shopify, Wix, Squarespace and Webflow issue the certificate and redirect http:// to https:// themselves once the domain is connected. If the checklist reports a problem there, check that the domain is connected through the platform's domain settings (not only pointed at it), and that the platform's SSL option is on.
Confirm the fix
Run the curl commands from Check it yourself again, then open the target in PulseKeeper and click Check now on the Checklist tab. If you also want browsers to skip http:// entirely from the second visit on, the next step is HSTS.