Take the 2-minute tour ×
Webmasters Stack Exchange is a question and answer site for pro webmasters. It's 100% free, no registration required.

I have WordPress 3.5.1 installed on Ubuntu 12.04 LTS. I'm running Apache 2.2.22.

NOTE: I can't share the domain that I'm working on, and must santize any config files and log outputs. While the website is public, any problems I'm working on in connection to the client cannot be made public.

Here is the problem I'm trying to solve:

  1. User lands on HTTP site.
  2. User goes to /order/ page and is redirected to the same page delivered over HTTPS.
  3. User clicks away from the order page, and the resultant URL is HTTPS. For example, say they click on the "About Us" link.
  4. The resulting HTTPS page loads all sorts of social media wingdings and libraries over HTTP.
  5. Warnings assail the visitor: "This site is not secure and you will surely die a vicious death! Abort! Abort!"

The solution I'm trying to implement is simple: Redirect all HTTP access to the /order/ page to HTTPS. Redirect all HTTPS access to non /order/ pages to HTTP.

(Side Note: I'm not using .htaccess files. I'm declaring the rewrite rules in the <Document> block in each sites config file.)

The website is Wordpress based and is using the standard mod_rewrite rules to make pretty URLs. Here is the HTTP vhost's rewrite rules:

            # Rewrite Rules. Suddenly dragons!
            RewriteEngine On

            # Redirect /order/ page to HTTPS
            RewriteCond %{HTTPS} =off
            RewriteRule ^order/$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

            # Wordpress Magicks Below
            RewriteRule ^index\.php$ - [L]

            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteRule . /index.php [L]

And now here's the SSL site's rewrite rules:

            # Rewrite Rules. Suddenly encrypted dragons!
            RewriteEngine On

            # Redirect all non /order/ page URLs to HTTP
            RewriteCond %{HTTPS} =on
            RewriteCond %{REQUEST_URI} !^/order/$
            RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

            # Wordpress Magicks Below.
            RewriteRule ^index\.php$ - [L]

            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteRule . index.php [L]

The Ugly Result:

Every access to /orders/ across HTTP or HTTPS is redirected to the home page over HTTP. The RewriteLog for the SSL vhost shows this ugliness:

68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] add path info postfix: /var/www/mysite.com/htdocs/order -> /var/www/mysite.com/htdocs/order/
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] strip per-dir prefix: /var/www/mysite.com/htdocs/order/ -> order/
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] applying pattern '(.*)' to uri 'order/'
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (4) [perdir /var/www/mysite.com/htdocs/] RewriteCond: input='on' pattern='=on' => matched
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (4) [perdir /var/www/mysite.com/htdocs/] RewriteCond: input='/order/' pattern='!^/order/$' => not-matched
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] add path info postfix: /var/www/mysite.com/htdocs/order -> /var/www/mysite.com/htdocs/order/
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] strip per-dir prefix: /var/www/mysite.com/htdocs/order/ -> order/
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] applying pattern '^index\.php$' to uri 'order/'
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] add path info postfix: /var/www/mysite.com/htdocs/order -> /var/www/mysite.com/htdocs/order/
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] strip per-dir prefix: /var/www/mysite.com/htdocs/order/ -> order/
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] applying pattern '.' to uri 'order/'
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (4) [perdir /var/www/mysite.com/htdocs/] RewriteCond: input='/var/www/mysite.com/htdocs/order' pattern='!-f' => matched
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (4) [perdir /var/www/mysite.com/htdocs/] RewriteCond: input='/var/www/mysite.com/htdocs/order' pattern='!-d' => matched
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (2) [perdir /var/www/mysite.com/htdocs/] rewrite 'order/' -> 'index.php'
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (3) [perdir /var/www/mysite.com/htdocs/] add per-dir prefix: index.php -> /var/www/mysite.com/htdocs/index.php
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (2) [perdir /var/www/mysite.com/htdocs/] strip document_root prefix: /var/www/mysite.com/htdocs/index.php -> /index.php
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b21380a0/initial] (1) [perdir /var/www/mysite.com/htdocs/] internal redirect with /index.php [INTERNAL REDIRECT]
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (3) [perdir /var/www/mysite.com/htdocs/] strip per-dir prefix: /var/www/mysite.com/htdocs/index.php -> index.php
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (3) [perdir /var/www/mysite.com/htdocs/] applying pattern '(.*)' to uri 'index.php'
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (4) [perdir /var/www/mysite.com/htdocs/] RewriteCond: input='on' pattern='=on' => matched
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (4) [perdir /var/www/mysite.com/htdocs/] RewriteCond: input='/index.php' pattern='!^/order/$' => matched
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (2) [perdir /var/www/mysite.com/htdocs/] rewrite 'index.php' -> 'http://mysite.com/index.php'
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (2) [perdir /var/www/mysite.com/htdocs/] explicitly forcing redirect with http://mysite.com/index.php
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (1) [perdir /var/www/mysite.com/htdocs/] escaping http://mysite.com/index.php for redirect
68.231.66.6 - - [06/Jun/2013:16:37:42 --0700] [mysite.com/sid#7f67b220e020][rid#7f67b213a778/initial/redir#1] (1) [perdir /var/www/mysite.com/htdocs/] redirect to http://mysite.com/index.php [REDIRECT/301]

I'll truncate the logs to the important bits, and comment on them:

RewriteCond: input='on' pattern='=on' => matched #HTTPS is on, so that pattern matches
RewriteCond: input='/order/' pattern='!^/order/$' => not-matched #It *is* the order page, so the negative match isn't a match
add path info postfix: /var/www/mysite.com/htdocs/order -> /var/www/mysite.com/htdocs/order/
strip per-dir prefix: /var/www/mysite.com/htdocs/order/ -> order/
applying pattern '^index\.php$' to uri 'order/' # Wordpress pretty URLs are applied
add path info postfix: /var/www/mysite.com/htdocs/order -> /var/www/mysite.com/htdocs/order/
strip per-dir prefix: /var/www/mysite.com/htdocs/order/ -> order/
applying pattern '.' to uri 'order/'
RewriteCond: input='/var/www/mysite.com/htdocs/order' pattern='!-f' => matched
RewriteCond: input='/var/www/mysite.com/htdocs/order' pattern='!-d' => matched
rewrite 'order/' -> 'index.php' # I... wait... NOOOOO!! And we're sent back to the home page.

The biggest problem here is that I'm not familiar enough with mod_rewrite or regex to know why this is happening exactly and how to remedy it. Can someone beat me with a clue bat?

share|improve this question
    
You have a couple of different resolutions available. You can fix the rules in .htaccess or avoid the whole thing by installing a plugin (wordpress.org/plugins/wordpress-https) and also fixing the various links to social media icons and libraries that are hardcoded to use http:// instead of // (stackoverflow.com/questions/4831741/…). –  JCL1178 Jun 7 '13 at 2:30
    
@JCL1178 You are the second person to recommend that plugin! I'm considering the plugin, but now I'd really like to understand the logic that is eluding me in the mod_rewrite rules. I will fight to the death! =) –  Wesley Jun 7 '13 at 2:55
add comment

1 Answer

up vote 3 down vote accepted

In the SSL config, move the first rule in the Wordpress Magicks up above your rule handling redirection.

        # Internal redirects, stop doing things!
        RewriteRule ^index\.php$ - [L]

        # Redirect all non /order/ page URLs to HTTP
        RewriteCond %{HTTPS} =on
        RewriteCond %{REQUEST_URI} !^/order/$
        RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php [L]

What's happening is that when the last rule catches (because you're requesting /order/), an internal redirect to index.php occurs. The internal redirect starts the rewrite process again.. and since the URI (internally) is now /index.php instead of /order/, the 301 rule matches on the second pass.

Putting the RewriteRule ^index\.php$ - [L] at the top of the rule set stops the rewriting process on the internal redirect, and should get /order/ to actually serve some real content over SSL.

share|improve this answer
    
Technically this was the solution, however from a Wordpress perspective something got completely mangled. The formatting of the page was without CSS when a user would click on the /order/ page. However, clicks away from that page to a different URL within the site would be regular HTTP. I'm looking at Wordpress plugins that handle forcing HTTPS on specific pages since it seems that Wordpress prefers to have things like this handled within the application. –  Wesley Jun 10 '13 at 21:14
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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