6

I'm trying to force non-www https in htaccess, but every example I find throws the error "too many redirects"

I want to redirect:

  • http://www.example.com
  • http://example.com
  • https://www.example.com

to:

  • https://example.com

The best explained solution I've found is here:
https://simonecarletti.com/blog/2016/08/redirect-domain-http-https-www-apache/

...Which gives the following example:

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

Thanks to the explanation I understand what it's doing, but I'm still getting the same error - too many redirects.

The best I have been able to do is:

RewriteCond %{HTTP_HOST} ^www.example.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]

...But of course that doesn't redirect http://example.com.

I have no redirects setup in httpd.conf, and None setup in Plesk. I'm on CentOS 6.8, Apache 2.2.15, Plesk 12.5.

What could be causing the issue?

RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
user2265915
  • 539
  • 3
  • 11
  • 22

1 Answers1

11

Adding the RewriteCond and RewriteRule you specify gives me ?off_example.com when using http:// or https://. Is that expected?

No, that's not the expected result - that will be the problem. HTTPS should be on when accessed over https://.... If the HTTPS server variable is never set to "on" (or rather, never changes from "off") then your RewriteRule will result in a redirect loop.

This suggests that the "Let's Encrypt addon in Plesk" is implemented via some kind of "proxy" (front-end) server? Your application server still responds over unencrypted HTTP to the proxy and the clients connection to the proxy is encrypted over HTTPS. At least, that's what it looks like - but your host should be able to confirm this.

If this is the case then the proxy usually sets additional HTTP request headers with details about the client's connection. You should be able to examine the request headers that your application sees, but it is common for the X-Forwarded-Proto header to be set with the protocol that is being used ("http" or "https"). If this is the case then you can probably change your existing directives to something like the following instead:

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,NE,R=301]

Another, less common method is for the (front-end) server to set an HTTPS environment variable (possibly provided by mod_ssl?) instead - note that this is different to the similarly named HTTPS server variable, as mentioned above. This environment variable is accessed using the syntax %{ENV:HTTPS} in the mod_rewrite directive and, if set, contains the same value as would otherwise be provided by the HTTPS server variable. For example:

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

Dynamic / Any Domain

How to make this with dynamic domain? I have multiple domains that I would like this directive to work on

Add a 3rd condition (RewriteCond directive), that always matches, in order to capture the domain name (less any www. subdomain) and change the RewriteRule directive accordingly.

For example:

:
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+?)\.?$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]

Where the %1 backreference in the substitution string contains the captured subpattern from the preceding condition (RewriteCond directive).

The regex ^(?:www\.)?(.+?)\.?$ also excludes the final dot (if any) in the case of a FQDN.

MrWhite
  • 43,179
  • 8
  • 60
  • 84
  • 1
    Your suggested solution works, thank you! Looking at the headers has reminded me that Cloudflare CDN is used, so I guess that's the proxy here? I see there are options out Cloudflare for SSL redirects described here: [link](https://support.cloudflare.com/hc/en-us/articles/200170416-What-do-the-SSL-options-mean) so now I guess I need to find out what most efficient solution is. – user2265915 May 04 '17 at 17:38
  • 1
    Cloudflare would indeed be the proxy - and if you are on the "Flexible SSL" option then you would need directives like the above. However, if you are on Cloudflare then setting a page rule might be the preferred option: [How do I redirect all visitors to HTTPS/SSL?](https://support.cloudflare.com/hc/en-us/articles/200170536-How-do-I-redirect-all-visitors-to-HTTPS-SSL-) – MrWhite May 04 '17 at 18:17
  • How to make this with dynamic domain? I have multiple domains that I would like this directive to work on – Moseleyi Jan 26 '23 at 12:05
  • @Moseleyi I've updated my answer for a "dynamic domain". You basically need to add a 3rd condition that captures the domain name and the `RewriteRule` directive then needs to be modified to use this. – MrWhite Jan 26 '23 at 12:24