Installing a certificate makes HTTPS available. It does not make anyone use it. Until you redirect, both versions of every page work, and visitors arriving from old links, bookmarks and search results stay on the insecure one indefinitely.
Partial HTTPS is worse than it appears. The session cookie identifying a logged-in user is sent with every request, including the plain HTTP ones, where anyone on the network path can read it. Securing only the login page protects almost nothing.
Before you redirect
Confirm HTTPS actually works first. Load the https:// address and check for a valid padlock with no certificate warning.
Redirecting to a broken HTTPS site makes the whole site unreachable rather than partly insecure; every visitor gets a certificate error and there is no working version left to fall back to.
Then take a copy of .htaccess. A mistake in a redirect rule produces a loop or a 500 across the entire site, and having the original beside it turns a crisis into a thirty-second fix.
The redirect
Add this to .htaccess in your site root, above the WordPress block if there is one:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
301 is permanent, which is what you want. It tells search engines the HTTPS version is now the address, and browsers cache it so repeat visitors skip the redirect entirely.
%{HTTP_HOST} preserves whichever hostname was requested, so the same rule works for the bare domain and www without hard-coding either.
Decide www or no-www at the same time
This is where redirect loops come from, and it is worth settling now rather than discovering it later.
If you also want to force www, do both in one rule rather than stacking two:
RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Or to force the bare domain:
RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1%{REQUEST_URI} [L,R=301]
Pick one form and make everything agree with it; the redirect, the application's configured site address, your sitemap and your canonical tags. Half the redirect loops in existence are an application set to the bare domain sitting behind a rule that forces www, each sending the visitor back to the other.
Test properly
Load the http:// address and confirm you land on https://. Then test a deep page; a post, a product, not only the homepage, because a rule can work at the root and mangle paths below it.
Check the redirect is a 301 instead of a 302:
curl -I http://example.com
A 302 is temporary and does not pass ranking signals the same way. If you see one, something else on the site is doing the redirecting: often a plugin, and two redirect mechanisms fighting is the other common cause of loops.
Update the application
The redirect handles visitors. It does not change the URLs your site generates itself.
In WordPress, set both WordPress Address and Site Address to the https:// form under Settings then General. If that locks you out, set them in wp-config.php instead, which overrides the stored values:
define( 'WP_HOME', 'https://example.com' ); define( 'WP_SITEURL', 'https://example.com' );
Then clear any caching layer. A cache holding HTTP versions of pages will keep serving them, which produces a very confusing few minutes where the redirect is correct and the site behaves as if it is not.
HSTS, once you are sure
HSTS tells browsers to use HTTPS for your domain without even trying HTTP, which removes the redirect round trip and closes the window where a first request travels unprotected.
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Add this only when HTTPS is working correctly everywhere, including every subdomain. Browsers remember it for the stated period, and a browser that has cached HSTS will refuse to load your site over HTTP even if you remove the header, so a mistake here is not quickly reversible.
Start with a short max-age, confirm everything works for a week, then raise it.
Afterwards
Update the site address in Search Console and analytics, and regenerate your sitemap, some plugins cache it and keep serving HTTP URLs until told otherwise.
Then check for mixed content, because the redirect does not fix resources requested over HTTP from within a page. There is more in fixing mixed content warnings.
When it goes wrong
Too many redirects. Two rules disagreeing, or the application configured for a different hostname than the rule enforces.
500 error across the site. A syntax error in .htaccess. Restore your copy.
Homepage redirects, other pages 404. The rule is dropping the path. Confirm %{REQUEST_URI} is present.
Redirect works, padlock still broken. Mixed content, not the redirect.
Some visitors still land on HTTP. Caching, at your server, at a CDN, or in their browser. Clear the first two and wait out the third.
Once HTTPS is settled, a few response headers close whole categories of attack. There is more on which are safe to add immediately in How to Set Up Website Security Headers.
A redirect still leaves one unencrypted moment, which a header can close: carefully, because browsers remember it: How to Set Up HSTS Safely.
The redirect loop that only happens behind a proxy
A rule that works on a plain server fails immediately behind a CDN or a load balancer, and the failure is total.
The reason is simple. The proxy accepts the secure connection and forwards the request to your server over plain HTTP. Your rule sees plain HTTP, redirects to the secure address, the proxy forwards it again, and the browser gives up after a number of hops.
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,END]
Testing both conditions means the rule fires only when the original request was genuinely insecure. Without the forwarded header check, the site is unreachable the moment a proxy is placed in front, which is frequently long after the rule was written and by somebody else.
The paths that must stay reachable over plain HTTP
A blanket redirect breaks two things that quietly depend on unencrypted access.
Certificate renewal is the important one. The validation request arrives at a well known path over plain HTTP, and a redirect can prevent it completing, so the certificate fails to renew and the site becomes unreachable weeks later for a reason nobody connects to this rule.
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
curl -sI http://example.com/.well-known/acme-challenge/test | head -1
The second is any health check or monitoring probe configured against the plain address. It will report the redirect rather than the site, which either produces false alarms or, worse, reports success while the application behind it is broken.
Clients that do not follow redirects
Browsers follow redirects silently, so testing in a browser hides the systems that do not.
An API consumer, a webhook sender, an old application or a script written with a simple request library frequently treats a redirect as the response. It reads a short page of redirect text instead of the data it expected, and either fails or stores nonsense.
curl -s -o /dev/null -w '%{http_code}\n' http://example.com/api/status
grep -E ' 30[12] ' ~/logs/example.com | awk '{print $7}' | sort | uniq -c | sort -rn | head
The second command lists which paths are still being requested insecurely and how often. Anything appearing regularly is a system that has not been updated, and telling its owner is more effective than waiting for it to notice. Setting up and reading uptime monitoring deals with the probes.