Good old regular expressions are driving me nuts.
I need to redirect all traffic in Apache 2.4 from HTTP to HTTPS, except for "/bt/sub/[a_few_endings]", using Redirect from mod_alias (can't use mod_rewrite).
I tested the following regular expression in all online testers I know (e.g. http://regex101.com/) and all confirm that the regex should indeed match everything except the URLs I don't want it to match:
^/(?!bt/sub/(went_active|success|cancel|expired)).*$
As far as I can tell, this should match everything in http://local.mysite.com and redirect it to https://local.mysite.com, except for the following four:
Still, Apache redirects everything, including the above URLs I don't want redirected.
I found several similar questions in SO but most of them are answered in the light of mod_rewrite, which is not what I want/need, and the ones that people say have worked have not worked for me.
Here's my virtual host configuration as it currently stands:
<VirtualHost *:80>
ServerName local.mysite.com
RedirectMatch 302 ^/(?!bt/sub/(went_active|success|cancel|expired)).*$ https://local.mysite.com
DocumentRoot /home/borfast/projects/www/mysite/public
#Header set Access-Control-Allow-Origin *
SetEnv LARAVEL_ENV localdev
<Directory /home/borfast/projects/www/mysite/public/>
Options All
DirectoryIndex index.php
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Please help and prevent me from going crazy :)
UPDATE: There's something weird going on: apparently when the requested URL/path can be found, Apache ignores the expression in RedirectMatch and redirects the client, even though the RedirectMatch tells it not to.
To test this I created a new virtualhost from scratch inside a separate VM freshly installed with Ubuntu Trussty 64, loaded with Apache 2.4. This new virtual host contained just the ServerName, RedirectMatch and DocumentRoot directives, like this:
<VirtualHost *:80>
ServerName testing.com
RedirectMatch 302 ^/(?!bt/sub/(went_active|success)$).*$ https://othersite.com/
DocumentRoot /home/vagrant/www
</VirtualHost>
I created the directory /home/vagrant/www/bt/sub/went_active
to make sure Apache could get to at least one of the two possible URLs. When trying to access http://testing.com:8080
, I get redirected, as expected.
Then the weirdness comes: when accessing http://testing.com:8080/bt/sub/went_active
, the URL that matches the directory I created, I am still redirected, even though I shouldn't be, but when accessing http://testing.com:8080/bt/sub/success
, I don't get redirected and instead get a 403 Forbidden.
I may be losing my sanity over this but it seems that when Apache sees that it could serve the request and it matches the regular expression in RedirectMatch that should prevent the redirect, it decides to ignore the regular expression and do the redirect anyway. Three letters for this: WTF?!?!?!
As it was said in comments - it is easier to do with mod_rewrite
. Possible solutions
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/bar/(abcd|baz|barista|yo)$ [NC]
RewriteRule ^ http://site/ [R=301,L]
Another one (for .htaccess, as initial /
is removed from RewriteRule
)
RewriteEngine On
RewriteRule !^bar/(abcd|baz|barista|yo)$ http://site/ [R=301,L,NC]
And solution by RedirectMatch
RedirectMatch permanent ^(?!/bar/(abcd|baz|barista|yo)$).* http://site/
All work perfectly, the problem that you might have on a testing/debugging state is that browser caches 301
response. So, when you are trying to check or to write the correct code - use 302
response, not 301
. And remove NC
flag if case insensitivity is not required.