How to combine Apache redirects? - apache

I've got an Apache config that features multiple rewrite rules and redirects in order to get the cutest URLs, prevent duplicates for SEO, etc. Here's a snippet as an example (it features a lot more):
# Redirecting non-www to www
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
# Removing index.php
RewriteCond %{REQUEST_URI} index\.php$ [NC]
RewriteRule .* / [R=301,L]
# A big bunch of these
Redirect permanent /old-article.html http://www.example.com/new-article.html
Redirect permanent /another-old-article.html http://www.example.com/new-article2.html
This works well, but it happens to generate a lot of redirects. A common case looks like this:
http://example.com/index.php, 301 redirect to http://www.example.com/index.php
http://www.example.com/index.php, 301 redirect to http://www.example.com
It sometimes reaches 4-5 redirects.
Now, I want all these rules to be chained and generate only one 301 redirect, like this:
http://example.com/index.php, 301 redirect to http://www.example.com
I know I can spend an afternoon thinking and sorting the rules to a better match, and also that I can create combined rules. But that would complicate an already long file. I want a flag, operand or whatever that will execute all the rules as if they where internal and only issue the redirect once it has crawled every rule. Is this even possible?

It seems as if simply re-ordering this would get you what you want:
# A big bunch of these
Redirect permanent /old-article.html http://www.example.com/new-article.html
Redirect permanent /another-old-article.html http://www.example.com/new-article2.html
# Removing index.php
RewriteRule ^/index.php http://www.example.com/ [R=301,L]
# Redirecting non-www to www
RewriteCond %{HTTP_HOST} ^example.com
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
A direct request for an old article at the example.com domain:
http://example.com/old-article.html
Will result in a single redirect to:
http://www.example.com/new-article.html
A request for either http://example.com/index.php or http://www.example.com/index.php will result in a single redirect to:
http://www.example.com/
A request that doesn't match anything else will result in a single redirect from:
http://example.com/foo
To:
http://www.example.com/foo
This seems to cover all the bases. Have I missed anything?

Remove the [L] flag from your RewriteRules, and they will be combined automatically.

Related

htaccess - Redirecting all traffic to another domain except existing 301's

My htaccess file is filled with 301 redirects like such:
Redirect 301 /old-page.html https://www.example.com/new-page
There are about 100 of these redirects. What I would like to do is redirect all traffic going to the old site to go to the new site excluding the existing 301's
So if someone goes to old-site.com/old-page.html it will take them to new-site.com/new-page and if someone goes to old-site.com/random-page.html it will take them to new-site.com - just the home page.
Is it possible to do this using mod_rewrite and mod_alias without rewriting the current 301's?
You can keep all your 301 rules. Just insert this generic 301 rule below your existing rule:
# all existing 301 rules go here
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(?:www\.)?old-site\.com$ [NC]
RewriteRule ^ http://new-site.com/? [L,R=301]
You need to use a RewriteCond in front of all your rules like this:
RewriteCond %{HTTP_HOST} ^(?:www\.)domain\.com$ [NC]
If you want all the following rules to be processed as well DO NOT use the L (last) flag in the RewriteCond statement.
Source: Redirect all urls exactly, just change domain name

Using a .htaccess to RewriteRule and Redirect 301 at the same time?

I have a couple of specific URLs that I want to display differently on my website. For example I want "/contact.php" to become "/contact". So I added this to my .htaccess:
RewriteRule ^contact$ contact.php
And to avoid having 2 different URLS pointing to the same page, I also want to do a 301 redirect between the old URL and the new one:
Redirect 301 /contact.php http://www.example.com/contact
Each of the line above works well separately. But if I add them both in my htaccess, I have a redirect loop. How can I fix that?
In the end, if I either type "/contact" or "/contact.php", I want to see the contact page with the url "/contact".
Edit: I also tried things like that, and it doesn't work:
RewriteRule ^/contact\.php$ http://www.example.com/contact [R=301,L]
RewriteRule ^/contact$ /contact.php [L]
Yes it will indeed cause redirection loop since mod_rewrite rules are applied in a loop. Here value of REQUEST_URI changes to contact.php after first rule and to contact by your second rule.
To avoid this looping you need to use %{THE_REQUEST} in your external redirect rule as THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of some other rewrite rules. Example value of this variable is GET /index.php?id=123 HTTP/1.1.
Use this:
RewriteEngine On
# external redirect from /contact.php to /contact
RewriteCond %{THE_REQUEST} \s/+(contact)\.php\[\s?] [NC]
RewriteRule ^ /%1? [R=302,L]
# internal forward from /contact to /contact.php
RewriteRule ^(contact)/?$ $1.php [L,NC]
Change 302 to 301 once you make sure it is working fine for you.

How to redirect from domain to subdomain?

My site is www.mysite.com and I need to redirect any request to us.mysite.com.
So:
www.mysite.com ----> us.mysite.com
www.mysite.com/hello.php ----> us.mysite.com/hello.php
// etc
I tryed this but doesn't work:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^mysite.com$
RewriteRule (.*) http://us.mysite.com$1 [R=301]
It looks like your RewriteCond is only matching domains that start and end with mysite.com. This does not include www.mysite.com.
The following will 301 redirect anything NOT at us.mysite.com to us.mysite.com:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^us.mysite.com$
RewriteRule ^(.*)$ http://us.mysite.com/$1 [R=301]
There are several different solutions. The best one, both from SEO and User perspective, is the one-to-one 301 redirect. It preserves your link juice and at the same time redirects the client to the exact location on the new website.
If you have mod_alias enabled, I would suggest a simple
RedirectMatch 301 ^(.*)$ / http://new.domain.com/$1
The result instruction can be accomplished with
RewriteEngine On
RewriteRule (.*) http://new.domain.com/$1 [R=301,L]
The second one is the best choice if you need to chain multiple conditions and filters. For example, if you need to redirect only certain hosts or clients depending on User Agent header.
From here.

redirecting with virtual hosts except robots.txt

I'm having a complicated seo issue where google has indexed thousands of pages from one of my nameservers. I need to redirect every request 301 EXCEPT robots.txt
This is what I have so far, but its not working. The commented out portion is a section that i originally put (that works), except it doesnt account for robots.txt. The two lines under that are my failure attempt
<VirtualHost xx.xx.xx.xx:80>
ServerName ns2.example.com
#RedirectMatch permanent /(.*) http://example.new/$1
RewriteCond %{REQUEST_URI} !^/robots\.txt [NC]
RewriteRule ^(.*)$ http://example.new/$1 [R=301,L]
</VirtualHost>
Does anyone see my error? example.new is the site i want to redirect to
Does anyone see my error? example.new is the site i want to redirect to
For starters, it looks like you need to turn on the rewrite engine:
RewriteEngine On
that worked, except now its redirecting everything as http://example.com//whatever-page with two //
This line:
RewriteRule ^(.*)$ http://example.new/$1 [R=301,L]
Needs to have the / removed:
RewriteRule ^(.*)$ http://example.new$1 [R=301,L]
This is because the URI that the RewriteRule is matching against has a leading slash when in vhost/server config, so you don't need the slash after the hostname in your target.

add alias in front of each URL mod_rewrite apache

If any likes come in the format
http://localhost/index.php/bla...
I want to convert it to http://localhost/er/index.php/bla...
I'm trying the following but it seems to be looping the url indefinitely
RewriteRule ^localhost/index/php/(.*)$ localhost/er/index.php/$1 [R=301,L]
RedirectMatch 301 ^/localhost/index.php/(.*)$ localhost/er/index.php/$1
You've got 2 different things going on, a RewriteRule (mod_rewrite) and a RedirectMatch (mod_alias). You'll only need one, but neither of those can match against the hostname (localhost). If this has to only be limited to the "localhost" host, then you need to do this:
RewriteEngine On
RewriteCond %{HTTP_HOST} localhost$ [NC]
RewriteRule ^/?index\.php/(.*)$ /er/index.php/$1 [R=301,L]
Otherwise, you can just stick with mod_alias:
Redirect 301 /index.php/ /er/index.php/
Everything after /index.php/ will automatically get appended.