Force HTTPS and a Single Canonical Host

The [OR] canonicalization rule explained line by line, why it's one redirect not two, the X-Forwarded-Proto loop, and the HSTS upgrade.

Published 2026-10-03

Your site should answer on exactly one URL form — https://example.com or https://www.example.com, pick one — and every other combination should 301 to it. Two reasons: duplicate content (www and apex serving identical pages splits ranking signals) and certificate coverage (a cert that only covers one host shouldn’t have the other answering at all).

The combined rule, line by line

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [L,R=301]
</IfModule>
  • RewriteCond %{HTTPS} off [OR] — true when the request is plain HTTP. The [OR] joins it with the next condition instead of requiring both.
  • RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC] — true when the Host header is anything except the canonical host. ! negates; [NC] because Example.COM is the same host.
  • Together: “wrong scheme OR wrong host” → redirect. A request for http://example.com/x fails both checks and lands on https://www.example.com/x in one hop.
  • RewriteRule ^ …%{REQUEST_URI} — ^ matches every request; %{REQUEST_URI} carries the full original path including the leading slash, so no $1 capture or per-directory prefix worries apply.

That’s the generator’s output when Force HTTPS and the canonical-host rule are both on — one rule, one redirect, no chain.

When you’d rather split it

The !^www\.example\.com$ condition folds every non-canonical host into the canonical one — including other subdomains like blog.example.com if they share this document root. To upgrade the scheme without touching the hostname:

RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [L,R=301]

%{HTTP_HOST} in the first rule preserves whatever host the visitor asked for (blog. stays blog.), and the second rule only fires for the exact apex. Cost: the apex’s http://example.com → https://www.example.com journey takes two hops instead of one. For single-domain shared hosting the combined rule is the right default; for multi-subdomain docroots, split.

The redirect loop that eats CDN sites

ERR_TOO_MANY_REDIRECTS right after enabling Force-HTTPS almost always means a proxy: Cloudflare’s Flexible SSL, an AWS ELB, or some hosts’ TLS termination all forward to Apache over plain HTTP — %{HTTPS} is permanently off, so every request gets redirected to HTTPS, which arrives at Apache as HTTP again, forever.

The fix is to trust the proxy’s report instead:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

(Correct end-state on Cloudflare is Full or Full (strict) SSL anyway — Flexible encrypts visitor→CF but leaves CF→origin plaintext.)

Then consider HSTS

Once HTTPS canonicalization works, mod_headers can tell browsers to never try HTTP again:

<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

Two cautions: includeSubDomains commits all your subdomains to HTTPS — don’t send it if some subdomain can’t do TLS yet. And preload + submission to the HSTS preload list is effectively permanent; treat it as a one-way door, not a toggle. HSTS removes the first HTTP request’s redirect for repeat visitors — it’s the upgrade after the 301s are proven, not a substitute for them.

Verify all four variants

for u in http://example.com http://www.example.com https://example.com https://www.example.com; do
  curl -sI "$u" | head -2
done

You want: three of them returning 301 + Location: to the canonical form, and the canonical form itself answering 200 — no 302s, no second 301 hop, no loop.

The generator emits all of the above — tick Force HTTPS and pick your canonical host. The pieces it depends on are explained in mod_rewrite basics and the 301 redirects guide.