.htaccess rule to redirect entire site except for a couple pages is not working

.htaccess rule to redirect entire site except for a couple pages is not working - .htaccess files are extremely useful in many cases for users who either do not have root permissions or for users who simply aren't comfortable in making changes in their web server's configuration file. Trying to debug .htaccess not working isn't always the easiest thing to do, however, hopefully by checking the discuss below mentioned about htaccess, apache, mod-rewrite, , .htaccess common problems as well as the troubleshooting tips, you'll have a better grasp on what you may have to modify to get your .htaccess file running smoothly.Problem :


I've been pulling my hair out for a couple of days over an .htaccess issue. I have a list of redirects which are all being done in this format:



Redirect 301 /my-page/ https://www.example.com/my-page/


That works just fine, but I need to redirect all other pages except the homepage and the contact page to the homepage of the new site. That's where the trouble comes in. There are several well-documented solutions for this, but I can't get a single one to work. Below the list of redirects, but above the WordPress rules, I have tried several solutions. Here are the three basic setups I tried:



<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %REQUEST_URI !^contact
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]
</IfModule>





<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^contact - [L]
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]
</IfModule>





<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^(?!contact)(.+)$ https://www.example.com/ [R=301,L,NE]
</IfModule>


I've also tried every combination of RewriteBase /, an %HTTP_HOST, and a slash before the contact url that I can think of, as well as the [NC] flag.



But in every single situation, either nothing works at all, or the contact page is redirected with all of the other pages. I haven't had any trouble with the homepage, just the contact page. Oddly enough, if I remove the negative look-ahead in the first version, that code runs perfectly.


Solution :

First off, you should be testing with 302 (temporary) redirects to avoid caching issues. It's possible that you have some erroneous 301 (permanent) redirects cached by the browser. So you will need to make sure the browser cache is cleared before continuing. (You can also test with Chrome's object inspector open and the cache disabled - checkbox on the Network tab.)



You should also avoid mixing redirects from both mod_alias (Redirect and RedirectMatch) and mod_rewrite (RewriteRule). These two different modules work independently and at different times during the request, so it's most likely you will get a conflict. Your mod_alias Redirect directives, despite appearing earlier in the .htaccess file actually execute last and work on the original request. But in this case the redirect-everything RewriteRule will take priority.



The Redirect directive is also prefix-matching, so a redirect like you example: Redirect 301 /my-page/ ... with also match /my-page/foo and /my-page/foo/bar - should those be URLs on your site.



You need to convert your mod_alias Redirect directives to the equivalent mod_rewrite RewriteRule directive. For example:




Redirect 301 /my-page/ https://www.example.com/my-page/



is equivalent to:



RewriteRule ^(my-page/.*) https://www.example.com/$1 [R=302,L]


UPDATED To include @Stephen's correction from comments.



Note that $1 is a backreference to the captured group in the RewriteRule pattern.



However, if this should only match /my-page/ exactly (as I expect you require) and not /my-page/<everything> then append an end-of-string anchor to the RewriteRule pattern and remove the .* catch-all. For example:



RewriteRule ^(my-page/)$ https://www.example.com/$1 [R=302,L]


Obviously, if the new URL is different then this needs to be explicitly stated:



RewriteRule ^my-old-page/$ https://www.example.com/my-new-page/ [R=302,L]


NB: Test with 302s.




RewriteCond %REQUEST_URI !^contact
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]



The REQUEST_URI server variable contains the full URL-path, starting with a slash, so this condition to not match ^contact will always be successful (the CondPattern should read !^/contact), so /contact will end up being redirected.




RewriteRule ^contact - [L]
RewriteRule ^(.+)$ https://www.example.com/ [R=301,L,NE]



This will prevent /contact being handled by WordPress - so it just won't work at all.




RewriteRule ^(?!contact)(.+)$ https://www.example.com/ [R=301,L,NE]



This should be OK, however, you'll likely have to make an exception for index.php as well, to avoid conflicting with the WordPress front-controller (or make sure you only target the initial request). For example:



RewriteRule ^(?!(contact|index.php))(.+)$ https://www.example.com/ [R=301,L,NE]


OR



RewriteCond %ENV:REDIRECT_STATUS ^$
RewriteRule ^(?!contact)(.+)$ https://www.example.com/ [R=301,L,NE]






I've also tried every combination of RewriteBase /, an %HTTP_HOST, and a slash before the contact url that I can think of, as well as the [NC] flag.




RewriteBase is not relevant here, although it could potentially break the WordPress front-controller (depending how this is written). The argument to RewriteBase is only used when you have a relative path substitution - you are specifying an absolute URL. I'm not sure how you would be using %HTTP_HOST here? - again, this doesn't seem relevant.


Additionally, if you would like to do some further testing, give the htaccess tester tool a try. It allows you to specify a certain URL as well as the rules you would like to include and then shows which rules were tested, which ones met the criteria, and which ones were executed.

Comments

Popular posts from this blog

Rewrite in Mediawiki, remove index.php, .htaccess

.htaccess rewrite wildcard folder paths from host

Using .htaccess to set a cookie and 301 redirect