2

For WordPress, I have seen two different techniques to edit the .htaccess file for routing to HTTPS. What are the pros and cons of these:

Option #1

RewriteEngine On 
RewriteCond %{SERVER_PORT} 80 
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

When navigating to www.example.com, this solution returns status 302 and routes traffic to https://www.example.com

See here.

Option #2

# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

I believe this solution will return status 301. I have not tested because option #1 appears to work.

See here.

Here is the relevant block of my .htaccess file before applying either method.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{HTTPS} =on
    RewriteRule .* - [E=W3TC_SSL:_ssl]
    RewriteCond %{SERVER_PORT} =443
    RewriteRule .* - [E=W3TC_SSL:_ssl]
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteRule .* - [E=W3TC_ENC:_gzip]
    RewriteCond %{HTTP_COOKIE} w3tc_preview [NC]
    RewriteRule .* - [E=W3TC_PREVIEW:_preview]
    RewriteCond %{REQUEST_METHOD} !=POST
    RewriteCond %{QUERY_STRING} =""
    RewriteCond %{REQUEST_URI} \/$
    RewriteCond %{HTTP_COOKIE} !(comment_author|wp\-postpass|w3tc_logged_out|wordpress_logged_in|wptouch_switch_toggle) [NC]
    RewriteCond "%{DOCUMENT_ROOT}/wp-content/cache/page_enhanced/%{HTTP_HOST}/%{REQUEST_URI}/_index%{ENV:W3TC_SSL}%{ENV:W3TC_PREVIEW}.html%{ENV:W3TC_ENC}" -f
    RewriteRule .* "/wp-content/cache/page_enhanced/%{HTTP_HOST}/%{REQUEST_URI}/_index%{ENV:W3TC_SSL}%{ENV:W3TC_PREVIEW}.html%{ENV:W3TC_ENC}" [L]
</IfModule>

For either solution, is it correct that I should add the RewriteCond and RewriteRule entries immediately after RewriteBase / ?

1
  • 1
    You should use 301 status here, for SEO and performance and since it should be a permanent redirect. – Samuel Elh Oct 6 '17 at 23:07
2

The different .htaccess/mod_rewrite directives you see around are usually because of differences in the server configuration (nothing to do with WordPress) and where they are being used. There's no such thing as a one size fits all. (For instance, the above redirect may not work if you are behind an SSL proxy.) However, as with most things, there are often different ways of doing the same thing. So, you don't need to do it one specific way for it to work perfectly.

Option#1

RewriteCond %{SERVER_PORT} 80 
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]

By default, HTTP works on port 80, which is what this checks for. However, you could configure HTTP to work on a different port. In which case, this would fail.

As you've stated, this is a 302 (temporary) redirect. (The default status when you don't explicitly include the status code with the R flag.) Unless you are testing then an HTTP to HTTPS redirect is expected to be permanent. So, you would normally expect this to be a 301, ie. R=301. 301 redirects are cached by browsers and seen as a permanent change by search engines.

^(.*)$ - strictly speaking, the start and end anchors, ie. ^ and $, are entirely superfluous. ^(.*)$ is the same as (.*). However, some users find the former easier to read. So whatever you prefer. This simply grabs the entire URL-path and saves it in the $1 backreference, used later in the substitution.

https://www.example.com/$1 - Hardcoding the canonical hostname in the substitution is arguably more reliable. When passing this code to someone to use on their site, there is less margin for error. Server admins often argue that this is the way you should always do it (although I don't necessarily agree - I'm not a server admin). (Particularly if you have multiple domains and www vs non-www hostname differences.) However, hardcoding is... well... hardcoding. So, it's less portable.

This directive should only be used in .htaccess (or a directory context). If you used this directly in the server config (not that you would) you would get a double slash (//) in the redirected URL.

Option#2

RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

HTTPS is a server variable set by Apache. It is either off or on and works regardless of what port HTTP (and/or HTTPS) is being served on. It's also arguably easier to read than checking SERVER_PORT. However, HTTPS is not available on Apache 1.3 (although that really should not be a problem!). On most servers there will be no difference between checking %{SERVER_PORT} 80 and %{HTTPS} off.

R=301 - Good, it's a 301 (permanent) redirect. Which is usually what you want.

(.*) - No unnecessary anchors (see above). However, the $1 backreference is not being used in the substitution (%{REQUEST_URI} is used instead), so the parentheses are an unnecessary (minor) overhead and should be removed. This should be written .*, or simply ^.

https://%{HTTP_HOST}%{REQUEST_URI} - The HTTP_HOST server variable holds the hostname that is present in the request. If your site is accessible via multiple domains then this will hold whatever domain is being requested. If your SSL cert only covers one of these domains then this will break. This also does not canonicalise any www vs non-www differences - which would need to be done before this directive to avoid a potential double redirect (which is why you often see www and HTTPS redirects done together).

Because of the use of %{REQUEST_URI} in the substitution this rule can be used in either the server config or .htaccess file without modification.

Option#3

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

For either solution, is it correct that I should add the RewriteCond and RewriteRule entries immediately after RewriteBase /

Yes, that is a logical place to put it. (However, it could go before it, even before the RewriteEngine directive - technically, it doesn't matter.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.