.htaccess help: RewriteRule entire website - regex

I recently launched a website into it's production environment.
This entire website will be in this folder structure:
/root/v1/website.com/index.php
The help I need is with .htaccess. When I'm upgrading an environment I require 0 downtime, so I want to make the next version of the website in a folder named:
/root/v2/website.com/index.php and available to switch over immediately.
basically "flip a switch", by sending all traffic to the corresponding folder in the current version.
So for example, right now, I would like all traffic that goes from http://www.website.com/cookies/aregreat.php to be opened at:
/root/v1/website.com/cookies/aregreat.php
This would apply to images, js and css files too
And then I can obviously change the version from inside the .htaccess and the rest will work itself out.
I'm not familiar with RewriteRule and i'm not too great with regex, the closest I've got to solving the problem is:
RewriteEngine on
RewriteRule (.*) /../v1.0.0/$1
Which is probably totally wrong. Is this even possible?
All help is welcome.
Many Thanks,
Dan

If you really want 'all traffic' to use the new version, I would not use an .htacess file for this, but a symbolic link. In root you'd have one link 'released' that points to v1. Create it like this
ln -s /root/v1 /root/released
Point your vhost at released. When you want to switch, do a one line command:
rm -rf /root/released; ln -s /root/v2 root/released

How about configuring it in your apache virtual host configuration (DocumentRoot)?

If you need to do this in .htaccess, try this:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^domainname.com$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www.domainname.com$
RewriteCond %{REQUEST_URI} !folderV2/
RewriteRule (.*) /folderV2/$1 [L]
Note: I haven't tested this, I'm not 100% sure that it will work.

In an htaccess file in your document root (would be n /root/.htaccess):
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/v[0-9.]+/website.com
RewriteRule ^(.*)$ /v1/website.com/$1 [L]
You'd just need to change the v1 to whatever version you have and save the file and you'd flipped the switch.
Unfortunately this doesn't work, but this is the type of solution that I would like. Would it be possible to rewrite this to work on subdomains too?
Yeah, you can match against the %{HTTP_HOST} and backreference using the % symbol:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?(.*)$ [NC]
RewriteCond %{REQUEST_URI} !^/v[0-9.]+/%2
RewriteRule ^(.*)$ /v1/%2/$1 [L]
Here, %2 is going to be whatever matches after an optional www.. So if the URL is:
http://www.domain.com/cookies/aregreat.php
Then you should get rewritten to /v1/domain.com/cookies/aregreat.php, and:
http://cakes.domain.com/chocolate/cake.php
should get rewritten to /v1/cakes.domain.com/chocolate/cake.php, etc.

Related

Regex HTAccess Not functioning

So I have this rule in my .htaccess file. It correctly stops the rewrite for the "files" directory but none of the other directories. I expected this to not redirect the files, pdf, img, and account directories.
RewriteCond %{REQUEST_URI} !^/(files|pdf|img|account).*$ [NC]
I also tried it with
RewriteCond %{REQUEST_URI} ^/[^(files|pdf|img|account)].*$ [NC]
This stops the redirecting for the all the requested directories but also for the mobile site so I think this just breaks the whole rule set I have.
My rule set is kind of long it so for redirecting from our main site to m.mainsite for mobile devices. If it'd be useful to see the whole set please let me know.
Thanks.
Instead of REQUEST_URI try THE_REQUEST variable as THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of some rewrite rules.
RewriteCond %{THE_REQUEST} !/(files|pdf|img|account) [NC]
You can use these two condition statements instead of just the one. One for the directory and then one for anything inside the directory such as a file or another directory.
RewriteCond %{REQUEST_URI} !^/(files|pdf|img|account)/?$ [NC]
RewriteCond %{REQUEST_URI} !^/(files|pdf|img|account)/(.*)$ [NC]

Cannot undertand the mixed outcomes of an .htaccess re-write rule / regex

I have a simple website comprised of one page with a div that gets populated with ajax content based on the links the user selects. This site is running on an Apache server with an .htaccess file in the domain's root directory. Requests to www.mydomain.com are directed to scripts/index.php while requests for dynamic content (but not resource files) are directed to the same .php script with the requested content passed as a parameter (e.g., www.mydomain.com/myProject will be rewritten as scripts/index.php?dynContent=myProject).
My rewrite rules are below and for the most part they are performing those described tasks properly; however, I've encountered some URLs that do not match the second condition even though I would expect them to -- though this is the first time I've had to write rules for an .htaccess file so I don't really know what I'm talking about... A good example of a URL that fails the second condition is www.mydomain.com/about, but I've encountered many more just by testing random words/letters.
Can you tell me why www.mydomain.com/about fails the second condition? Also, if there is a more elegant way to achieve the objectives I described above, I would love to learn about it. Thank you!!
RewriteCond %{HTTP_HOST} ^(www.)?mydomain.com$ [NC]
RewriteRule ^(/)?$ scripts/index.php [L]
RewriteCond %{REQUEST_URI} .*[^index.php|.css|.js|.jpg|.html|.swf]$
RewriteRule .* scripts/index.php?dynContent=$1 [L]
This is because regex in your 2nd rules is incorrect.
Change your code to:
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$ [NC]
RewriteRule ^(/)?$ scripts/index.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.(php|css|js|jpe?g|html|swf)$
RewriteRule ^(.*)$ scripts/index.php?dynContent=$1 [L]

htaccess subdomain pointing

I need some help on the htaccess subdomain to be pointed to specific file in a folder.
Inside the parent folder should contain individual php files to correctly path the right applications. Sounds simple here.
The url that the user has type should not change / redirect, instead it should only
"link" to the correct file at the background
Example when user type userbase.company.com it should point to
http://company.com/parent/userbase.php
Similarly, when user type userbase2.company.com it should point to
http://company.com/parent/userbase2.php
but no redirection should happen. url links should remain at
http://userbase2.company.com
folder would be the same, but not the file. Is it possible?
Currently I have this htaccess code:
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} ^userbase.company.com$ [OR]
RewriteCond %{HTTP_HOST} ^www.userbase.company.com$
RewriteRule ^(.*)$ \./parent/userbase.php/$1 [L]
I'm going have to put this at /public_folder/ right? Not at the /public_folder/userbase ?
This rule should do the job:
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !^/parent/
RewriteCond %{HTTP_HOST} !=domain.com
RewriteCond %{HTTP_HOST} !=www.domain.com
RewriteCond %{HTTP_HOST} ^([^\.]+)\.domain\.com$
RewriteRule (.*) /parent/%1.php%{REQUEST_URI} [L]
URL will remain unchanged in browser (means rewrite -- internal redirect).
It will only work for something.domain.com (not domain.com or www.domain.com).
It will rewrite this request http://user1.company.com/hello/pink/kitten.php into /parent/user1.php/hello/pink/kitten.php
If subdomain is complex (e.g. www.something.domain.com) then it will be reflected in rewrite as well: e.g. http://www.something.company.com/hello/pink/kitten.php will be rewritten to /parent/www.something.php/hello/pink/kitten.php. If such behaviour is undesired (I do not know your requirements for 100%) then you will need add 1 more condition to the rule.
Request for a home page (e.g. http://user1.company.com/) will be rewritten in this way: /parent/user1.php/
P.S.
Rule was tested before posting -- works fine, but you have to check and maybe tweak it if it needs to be working with your CodeIgniter app (sorry, I'm not familiar with that framework).
In any case this rule should be above your CodeIgniter rewrite rules (if there are such).

RewriteCond in .htaccess with negated regex condition doesn't work?

I'm trying to prevent, in this case WordPress, from rewriting certain URLs. In this case I'm trying to prevent it from ever handling a request in the uploads directory, and instead leave those to the server's 404 page. So I'm assuming it's as simple as adding the rule:
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/
This rule should evaluate to false and make the chain of rules fail for those requests, thus stopping the rewrite. But no... Perhaps I need to match the cover the full string in my expression?
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/.*$
Nope, that's not it either. So after scratching my head I do a check of sanity. Perhaps something is wrong with the actual pattern. So I make a simple test case.
RewriteCond %{REQUEST_URI} ^/xyz/$
In this case, the rewrite happens if and only if the requested URL is /xyz/ and shows the server's 404 page for any other page. This is exactly what I expected. So I'll just stick in a ! to negate that pattern.
RewriteCond %{REQUEST_URI} !^/xyz/$
Now I'm expecting to see the exact opposite of the above condition. The rewrite should not happen for /xyz/ but for every other possible URL. Instead, the rewrite happens for every URL, both /xyz/ and others.
So, either the use of negated regexes in RewriteConds is broken in Apache, or there's something fundamental I don't understand about it. Which one is it?
The server is Apache2.
The file in its entirety:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/
RewriteRule . /index.php [L]
</IfModule>
WordPress's default file plus my rule.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_URI} !^/wp-content/uploads/ [OR]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
So, after a lot of irritation, I figured out the problem, sort of. As it turned out, the rule in my original question actually did exactly what it was supposed to. So did a number of other ways of doing the same thing, such as
RewriteRule ^wp-content/uploads/.*$ - [L]
(Mark rule as last if pattern matches) or
RewriteRule ^wp-content/uploads/.*$ - [S=1]
(Skip the next rule if pattern matches) as well as the negated rule in the question, as mentioned. All of those rules worked just fine, and returned control to Apache without rewriting.
The problem happened after those rules were processed. Instead, the problem was that I deleted a the default 404.shtml, 403.shtml etc templates that my host provided. If you don't have any .htaccess rewrites, that works just fine; the server will dish up its own default 404 page and everything works. (At least that's what I thought, but in actual fact it was the double error "Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.")
When you do have a .htaccess, on the other hand, it is executed a second time for the 404 page. If the page is there, it will be used, but now, instead the request for 404.shtml was caught by the catch-all rule and rewritten to index.php. For this reason, all other suggestions I've gotten here, or elsewhere, have all failed because in the end the 404 page has been rewritten to index.php.
So, the solution was simply to restore the error templates. In retrospect it was pretty stupid to delete them, but I have this "start from scratch" mentality. Don't want anything seemingly unnecessary lying around. At least now I understand what was going on, which is what I wanted.
Finally a comment to Cecil: I never wanted to forbid access to anything, just stop the rewrite from taking place. Not that it matters much now, but I just wanted to clarify this.
If /wp-content/uploads/ is really the prefix of the requested URI path, your rule was supposed to work as expected.
But as it obviously doesn’t work, try not to match the path prefix of the full URI path but only the remaining path without the contextual per-directory path prefix, in case of the .htaccess file in the document root directory the URI path without the leading /:
RewriteCond $0 !^wp-content/uploads/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .+ /index.php [L]
If that doesn’t work neither, it would certainly help to get some insight into mod_rewrite’s rewriting process by using its logging feature. So set RewriteLogLevel to a level of at least 4, make your request and take a look at the entries in the log file specified with RewriteLog. There you can see how mod_rewrite handles your request and with RewriteLogLevel greater or equal to 4 you will also see the values of variables like %{REQUEST_URI}.
I have found many examples like this when taking a "WordPress First" approach. For example, adding:
ErrorDocument 404 /error-docs/404.html
to the .htaccess file takes care of the message ("Additionally, a 404 Not Found error...").
Came across this trying to do the same thing in a Drupal site, but might be the same for WP since it all goes through index.php. Negating index.php was the key. This sends everything to the new domain except old-domain.org/my_path_to_ignore:
RewriteCond %{REQUEST_URI} !^/my_path_to_ignore$
RewriteCond %{REQUEST_URI} !index.php
RewriteCond %{HTTP_HOST} ^old-domain\.org$ [NC]
RewriteRule ^(.*)$ http%{ENV:protossl}://new-domain.org/$1 [L,R=301]

Temporary redirect 302 with .htaccess and mod-rewrite matching expression

I'm trying to match a a bunch of redirects for my website with basically moved to a different folder on the server. I need to make http://www.site.com/index.php?page=anypage go to http://www.site.com/newfolder/index.php?page=anypage. The thing is http://www.site.com/index.php and http://www.site.com/index.php?page=home should remain untouched. How can I accomplish this?
I was trying the following in the .htaccess file, but I am affraid to make a mistake. I really don't know how to test this, either.
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^/index.php?page=(.*)$ http://www.site.com/newfolder/index.php?page=$1 [R=302,NC]
RewriteRule ^/index.php?page=home http://www.site.com/index.php?page=home [R=302,NC,L]
Now I figured that this is temporary, so I should know ho to reverse it! The next week, the links will have to redirect again to the root server. Also, what should I do to re-establish the normal redirection??
If I've followed your scenario correctly, you want something like this:
RewriteEngine On
RewriteCond %{QUERY_STRING} !=""
RewriteCond %{QUERY_STRING} !page=home
RewriteRule ^index.php /newfolder/index.php [R,L]
As far as testing goes, I prefer to try rules out on a local test server. If you have full control over the server (as is the case locally), there are some mod_rewrite directives that help you log what's going on, and that can be helpful in debugging. The module documentation has more information about this.
Edit: When you want to switch back, modify the RewriteRule above like so:
RewriteRule ^newfolder/index\.php /index.php [R,L]