Https to http with variant exceptions - apache

Our site is going to be switched to SSL soon but we're not ready for it. As such we are going to redirect all https URLs to http in htaccess. I've got that working but as an added complication we've got a few URLs that have to be exceptions to the redirect. These URLs are:
somebody.dev.www.example.com
example.com/top_deal
example.com/watches
I have the redirect working like so:
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=302]
but can't get the exceptions to work. I've tried literally every solution online that I can find.

You can use rule as your very first rule:
RewriteEngine On
RewriteCond %{HTTP_HOST} !=somebody.dev.www.example.com
RewriteCond %{THE_REQUEST} !\s/+(?:top_deal|watches)/?[?\s] [NC]
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
# rest of your rules go here
Make sure to clear your browser cache before testing.

First, do you want it to be a temporary rewrite (=302) or should the browser save it as permanent und thus get 301? Just asking, both works, but if you want to go for temporary, you should read this
Excerpt: HTTP/1.1 (RFC 2616) added the new status codes 303 and 307
So in your case a 307 would probably be better.
If you want to have permanent rewrite instead, use [R=301] to make the browser cache the rewrite-target instead of rewriting each time.
Now to the WRONG solution (but there is a good reason I leave in there, see here) - DON'T use that !!!
#logic is: 1 OR (2 AND 3) --> NO, it isn't, see the link right above!
#1 being hostname: somebody.dev.www.example.com
#2 being hostname: example.com
#3 being REQUEST_URI = !^/(top_deal|watches)
RewriteCond %{HTTP_HOST} ^somebody.dev.www.example.com$ [OR]
RewriteCond %{HTTP_HOST} ^example.com$
RewriteCond %{REQUEST_URI} !^/(top_deal|watches)$
RewriteRule .? - [END]
##[END] makes the rewrite-evaluation STOP, completely, not only for this turn!
#same rule as before, just changed 302 -> 307 (RFC 2616) and ^(.*)$ to .? cuz I like it better^^
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule .? http://%{HTTP_HOST}%{REQUEST_URI} [L,R=307]
Update
Here is, what really should be put into your config:
# Don't rewrite HOST 'somebody.dev.www.example.com'
RewriteCond %{HTTP_HOST} ^somebody.dev.www.example.com$
RewriteRule ^ - [END]
# Don't rewrite HOST 'example.com', if URI 'top_deal' OR 'watches'
RewriteCond %{HTTP_HOST} ^example.com$
RewriteCond %{REQUEST_URI} ^/(top_deal|watches)$
RewriteRule ^ - [END]
RewriteCond %{HTTPS} on
RewriteRule ^ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=307]
That should definitely do the job :)
If it doesn't, for some reason, search for your LogLevel and add the rewrite:traceX to that line. So if your LogLevel is error it should look like this:
LogLevel error rewrite:trace2
Then restart/reload your server and test again. Error.log will now show the results of the attempted rewrites. Use tail -f error_log|fgrep '[rewrite:' to find them. If they are unclear, let us know, maybe we can help :)

What I finally did that ended up working was the following:
RewriteCond %{HTTP_HOST} !^(.*).dev.www.example.com
RewriteCond %{REQUEST_FILENAME} ! top_deal(.*)
RewriteCond %{REQUEST_FILENAME} ! watches(.*)
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteRule .? http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Related

Force HTTPS and WWW in .htaccess

I start reading about a similar topic at this page .htaccess - how to force "www." in a generic way? and the solution was not, well almost what I am looking to do.
The problem : I need the user to be on HTTPS and on WWW to make my application working properly. But if some one click on a html link like:
www.example.com
The user will fall on my website with this :
https://www.www.example.com/
Here is my current .htaccess file.
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://www.%{SERVER_NAME}/$1 [R=301,L]
</IfModule>
Is there any way to detect that the user already entered the WWW or is there a best practice to get the result I am looking for?
Thank you.
You are getting this behavior because http -> https rule is adding www\. in target URL without checking if URL is already starting with www.
You should replace both of your rules with this single rule and as a bonus avoid multiple redirects:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]

Can't get htaccess rule to work: force SSL on all pages, force non-SSL on two specific pages

I am no htaccess expert, but after Googling for two hours I gave up. Maybe you can help me?
I have my entire site on SSL. However, I have two pages that reference non-secure dynamic content from elsewhere. I need these to be on http instead of https.
The first part of my rules work. All the site is forced to SSL except for those two pages. However, the last part doesn't: force those two pages to non-SSL. It is probably very stupid but does anyone see where I go wrong?
#add www. if missing WORKS
RewriteEngine on
RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [L,R=301]
#force SSL/https WORKS
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_URI} !^/webshop2/localize\.php
RewriteCond %{REQUEST_URI} !^/webshop2/layoutstripper\.php
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
#force http DOES NOT WORK
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} ^/webshop2/localize\.php [NC]
RewriteCond %{REQUEST_URI} ^/webshop2/layoutstripper\.php [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
You need an [OR] flag in your second SSL rule. The 2 conditions you have essentially say:
the request must be HTTPS
the URI must start with: /webshop2/localize.php
the URI must start with: /webshop2/layoutstripper.php
As you can see, the last 2 conditions will always fail, as the request can't be BOTH at the same time. If you add an [OR] flag in there, it makes it true if the URI is one or the other:
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} ^/webshop2/localize\.php [NC,OR]
RewriteCond %{REQUEST_URI} ^/webshop2/layoutstripper\.php [NC]
RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteCond "except for directory" failing in complex rule set

I need to force everything except IE8 to HTTPS and IE8 specifically to HTTP
(it's temporarily - hence the 302 - its stupid, but there are legit business reasons).
I want all of this to ignore the /api/ directory as the app that utilizes these sadly doesn't follow redirects.
The following is working, IE8 detection is working. Everything is except /api/whatever is still being redirected.
I'd really appreciate any advice or an explanation of why this is not working.
# make sure mod_rewrite is ON
RewriteEngine On
# force staging and live to SSL
RewriteCond %{HTTPS} !=on
# Unless its IE 8
RewriteCond %{HTTP_USER_AGENT} !compatible;\sMSIE\s8\.0 [NC]
RewriteCond %{HTTP_HOST} ^(www\.|staging\.)?example\.com [NC]
# Skip the API
RewriteCond %{REQUEST_URI} !^/api/.*
# 301 Permanent
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301]
# force IE8 to Non-SSL
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_USER_AGENT} compatible;\sMSIE\s8\.0 [NC]
RewriteCond %{HTTP_HOST} ^(www\.|staging\.)?example\.com [NC]
# Skip the API
RewriteCond %{REQUEST_URI} !^/api/.*
# 302 Temporary
RewriteRule .* http://%{SERVER_NAME}%{REQUEST_URI} [L,R=302]
Don't see anything wrong, though assuming that you've cleared your browser's cache, you could try a different approach and include an explicit pass-through at the top of your list of rules:
RewriteRule ^api/ - [L]
You can add that right under RewriteEngine On and get rid of the /api conditions.
The RewriteCond %{REQUEST_URI} !^/api/.* was working, the problem was a later rewrite routing everything through a front controller /index.php was causing the htaccess to reparse.
Changing the rule to RewriteCond %{REQUEST_URI} !^(/api/|/index.php) solved the problem. the front controller, index.php isn't callable directly anyway, so it's not an issue.

Apache, url rewrite

I have the following .htaccess file inside my root directory:
RewriteEngine On
<If "%{SERVER_NAME} = 'example.com'">
# The actual condition is really long one so I replaced it for illustration.
RewriteCond %{HTTP_USER_AGENT} (iPhone|Blackberry|Android) [NC]
RewriteRule .* http://m.example.com%{REQUEST_URI} [R,L]
RewriteCond %{REQUEST_URI} ^/([a-z-]+)/$ [NC]
RewriteRule .* %{REQUEST_SCHEME}://%{SERVER_NAME}/?title=%1 [L]
</If>
<Else>
RewriteCond %{REQUEST_URI} ^/([a-z-]+)/$ [NC]
RewriteRule .* %{REQUEST_SCHEME}://%{SERVER_NAME}/?title=%1 [L]
DirectoryIndex /m/index.htm /m/index.php /m/index.html
</Else>
So as you can see its a pretty much simple way to redirect users of mobile devices to m.example.com and if that is the case I change the DirectoryIndex, few notes:
The reason I duplicate the same RewriteCond/RewriteRule is because I can't use them outside <If>/<Else> blocks.
The way I redirect(if/else) is not the question and I'm pretty sure not the best way, but if anyone have suggestions I'm all ears.
The problem:
If I access example.com/Article-Name on desktop browser there will be internal redirection to: example.com/?title=articleName but I won't see example.com/?title=articleName at my url bar as expected.
The exception:
If I access m.example.com/Article-Name my url bar is now m.example.com/?title=articleName.
I was expecting the same behavior as the desktop (internal redirection not redirection I can see on my url bar), I'm pretty sure its because the DirectoryIndex but I don't how to prove it or solve this issue, if anyone have a solution I will be very thankful.
The main issue with your code is that you're feeding it with an URL that is not the same as the current URL then, what happens is that it ignores the internal and make it an external redirect.
Another very important thing is that you forgot %{HTTP_USER_AGENT} to match against the mobile browsers.
Here is an idea to resolve your issue:
RewriteEngine On
# First we verify if its a mobile device and
# if its not already on the mobile subdomain
RewriteCond %{HTTP_HOST} !^m\.domain\.com$ [NC]
RewriteCond %{HTTP_USER_AGENT} (iPhone|Blackberry|Android) [NC]
RewriteRule ^ http://m.example.com%{REQUEST_URI} [R,L]
# here we deal with all the internal redirects for
# the mobile subdomain
RewriteRule ^m/index\.php$ - [L]
RewriteCond %{HTTP_HOST} ^m\.domain\.com$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ /m/index.php?title=$1 [L]
# here we deal with the normal website
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ /index.php?title=$1 [L]
Your doing internal redirects, if you want to redirect to a new URL use external ones
Replace [L] with [L,R=302]
or 301 if you want the result to be cached

htaccess from https to http

I have these vales in my htacces file it all works fine except when i try to go back to http from https i have tried swapping the rules around with no success, any help would be awsome
I have tried all the sujestion with still no suucess so maybe i need to show you guys the entire thing.
Still not going back to http from https, here is the whole thing
Have i got the rules in the wrong order? im lost
<ifModule mod_rewrite.c>
RewriteEngine on
# For Sales:
RewriteRule ^shop/sales/?$ sales.php
# For the primary categories:
RewriteRule ^shop/([A-Z-Aa-z\+]+)/?$ shop.php?type=$1
# For specific products:
RewriteRule ^browse/([A-Za-z\+]+)/([A-Za-z\+\-]+)/([0-9]+)$ browse.php?type=$1&category=$2&id=$3
#For https pages:
#RewriteCond %{HTTPS} on
#RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L=301]
#RewriteCond %{HTTPS} off
#RewriteRule ^(checkout\.php|final\.php|admin/(.*))$ https://{HTTP_HOST}/$1[R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1 [L,QSA]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s(.*)/index\.php [NC]
RewriteRule ^ /%1 [R=301,L]
</ifModule>
I am not able to test the rules, but I think you need to change the following:
In the first rule your flag is attached to the 2nd argument. This should create an internal error. Your second rule would rewrite all url's to their http equivalent, making an infinite loop. You need to make sure it doesn't match url's that you want to be in https. You can do this with %{REQUEST_URI} and a negation (!). As far as I am aware, L=301 is an invalid flag too. You probably meant to make it R=301.
RewriteCond %{HTTPS} off
RewriteRule ^(checkout\.php|final\.php|admin/(.*))$ https://{HTTP_HOST}/$1 [R,L]
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !/(checkout\.php|final\.php|admin/(.*))$
RewriteRule ^http://%{HTTP_HOST}%{REQUEST_URI} [R,L]
Last but not least an word of advice. Don't test your .htaccess with permanent redirects until everything works as expected. The browser will cache permanent redirects, not picking up further tries to make your .htaccess work as you want.