Search code examples
apache.htaccesshttp-redirectmod-rewrite

Making .htaccess more efficient


I have an .htaccess that I've cobbled together over the years using this site as a guide but hoping I can consolidate some of the lines to make it more efficient.

These lines do three things:

  1. Redirect any non-www requests to the www variant;
  2. Redirect any .com requests to the proper .org TLD;
  3. Redirect any http to the proper https variant; 3.

Here's what I have:

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteEngine On
RewriteCond %{http_host} ^example.com
RewriteRule ^(.*) https://www.example.org/$1 [R=301,L]
RewriteEngine On
RewriteCond %{HTTP_HOST} example\.org [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.org/$1 [R,L]

Is there a way to combine (at least some) of these functions into fewer lines?

I'm NOT having any problems, it's just the organizer in me that feels it could be neater.....

Thanks in advance for any suggestions!


Solution

  • # Rule #1
    RewriteCond %{HTTP_HOST} !^www\.
    RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
    
    # Rule #2
    RewriteCond %{http_host} ^example.com
    RewriteRule ^(.*) https://www.example.org/$1 [R=301,L]
    
    # Rule #3
    RewriteCond %{HTTP_HOST} example\.org [NC]
    RewriteCond %{SERVER_PORT} 80
    RewriteRule ^(.*)$ https://www.example.org/$1 [R,L]
    

    Yes, your rules can be optimised. Not least because they don't actually do what you say they do!

    (I'm assuming you have no intention to implement HSTS?)

    1. Redirect any .com requests to the proper .org TLD;

    These directives don't actually redirect the .com variant to .org, as you suggest in your 2nd requirement. If you are seeing this redirect then it's not because of these directives. Most probably WordPress itself is doing this, later in the request.

    For example...

    Scenario #1:

    • Request http://www.example.com/ (or https://www.example.com/)
    • No redirects occur since the requested host does not match rule #1, #2 or #3
    • The request is not redirected to .org (or HTTPS in the case of a request to http://...)

    scenario #2:

    • Request http://example.com/ (or https://example.com/)
    • Redirect to https://www.example.com/ (same domain) by rule #1
    • No further redirects occur as stated in "Scenario #1" above.
    • The request is not redirected to .org.

    As you can see from these examples your rule #2 (that matches example.com only) doesn't actually do anything. It is always bypassed because rule #1 has already redirected the request to the www subdomain. It would be "better" if rule #1 and #2 were reversed, however, that still wouldn't resolve the issue when www.example.com (www subdomain) was requested, as nothing would happen still.

    Other notes:

    • Rule #3 - HTTP to HTTPS redirect - is a temporary (302) redirect. This should be a 301, like the others.
    • No need to repeat the RewriteEngine On directive. It only needs to occur once in the file. (It is often seen repeated when .htaccess files are edited by "the machine", not code "by hand".) For readability, this should be at the top of the file. However, if you have multiple RewriteEngine directives it's actually the last instance that wins and controls the entire file (which may not be intuitive). eg. If you put a RewriteEngine Off directive at the very end of the .htaccess file then... it's off for the whole file, despite any RewriteEngine directives you might have preceding this.

    Simplified (and "fixed"):

    1. Redirect any non-www requests to the www variant;
    2. Redirect any .com requests to the proper .org TLD;
    3. Redirect any http to the proper https variant; 3

    These 3 requirements are only satisfied if everything redirects to www + .org + HTTPS. ie. Everything must redirect to https://www.example.org/ (the canonical URL).

    So, your existing 3 rules can be reduced to a single rule, in order to satisfy your 3 requirements. ie. If the request is not for https://www.example.org/ then redirect to https://www.example.org/.

    RewriteEngine On
    
    # If not the canonical host OR not HTTPS then redirect to HTTPS + canonical host
    RewriteCond %{HTTP_HOST} !^www\.example\.org$ [OR]
    RewriteCond %{SERVER_PORT} 80    
    RewriteRule (.*) https://www.example.org/$1 [R=301,L]
    

    We don't need to reference example.com at all here, since we are only concerned whether it is not the canonical host.

    And, since this is a WordPress site, this redirect must go before the WP front-controller, near the top of your .htaccess file.