Using Redirects and mod_rewrite to implement 301 redirects in Apache

You have a couple of options when doing redirects in Apache. The simpler of the two methods to do 301 redirects with Apache is to use the Redirect directive. To redirect myserver.com/old-page to myserver.com/new-page, you can add the following to your http.conf or your virtualhost file (depending on your setup):

Redirect 301 /old-page /new-page

If you neglect to add the 301, Apache defaults to a 302 temporary redirect which is usually not desired. If you want to make what’s going on more clear to you later on, you can also use “permanent” instead of 301 like

Redirect permanent /old-page /new-page

You can find more information about the other redirect methods you can implement here.

After restarting your Apache web server, you can test to see if your redirect is working as intended by using curl in the command line.

$ curl -i myserver.com/old-page
HTTP/1.1 301 Moved Permanently
...

If you see 301 Moved Permanently, your redirect is working as you intended. If you see 404 Not Found or some other status code like 200 Successful, you might need to check to make sure what you added was as intended.

Peculiarities

Now, we ran into a slightly more complicated problem this week that cannot be solved by the Redirect directive. One of the properties of the redirect method is that all subfiles and subdirectories are also rediected. So, for example, if you are redirecting myserver.com/old-page to myserver.com/new-page, any subdirectories or files under old-page will also be redirected. So that means that myserver.com/old-page/users.html will be redirected to myserver.com/new-page/users.html. So what happens if you want to redirect /old-page to /new-page but want to leave files and directories like users.html under /old-page intact with the old path? This is where mod_rewrite comes in.

mod_rewrite is a little more complicated to use than the Redirect directive we used above, but you’ll find that it is also quite a bit more powerful. Using mod_rewrite allows you to write redirects based on pattern matching in the url. What this means is that you can have Apache decide, based on a pattern you give it, whether or not a redirect will be necessary for a given URL.

First off, you’ll need to enable mod_rewrite for your server. This can vary based on the version of Apache you’re using and may already be enabled, in either case, you should be able to find some solutions by following some of these links. We’re going to be redirecting /old-path to /new-path but making sure everything under /old-path stays the same. So, for example, myserver.com/old-path will 301 redirect to myserver.com/new-path but myserver.com/old-path/users.html will stay the same. Once you have figured out how to enable mod_rewrite, open up the configuration file from earlier and add the following:

RewriteEngine on
RewriteCond %{REQUEST_URI} ^/old-path[/]?
RewriteCond %{REQUEST_URI} !^/old-path/+[/]?
RewriteRule (.*) /new-path [R=301,L]

So a little wordier than the Redirect directive above, but a lot more going on behind the scenes, even in a simple example like this one. What this accomplishes is by taking the REQUEST_URI (everything after myserver.com, so in this instance /old-path) and then running it through a pattern matcher. The first condition checks to see if the REQUEST_URI is equal to /old-path with an optional slash (the question mark makes the preceding character optional) and then the second condition rejects (by using the ! point) any path that has characters after /old-path/. When the conditions are met (i.e. when /old-path or /old-path/ are the REQUEST_URI), the RewriteRule is invoked. In this case, that does a 301 redirect to /new-path.

A little more complicated than using the simple Redirect directive, but considering the amount of power pattern-matching allows you, there are many cases where you'll be forced to rely on it. If you want to dig a little deeper with mod_redirect, Apache has many wonderful pages of documentation that can point you in the right direction.

Redirects in Ruby on Rails 3+

Now for the Ruby on Rails developers out there, should you want to avoid diving into your server configs and you are using a Rails 3.x or 4.x app, you can do simple 301 redirects directly from your routes.rb file.

To implement a 301 redirect on an old url myserver.com/old-page to myserver.com/new-page, its as simple as adding the following to your routes.rb file:

match /old-page, :to => redirect(/new-page’)

now if you deploy these changes and hit it with curl, you should see the following:

$ curl -i myserver.com/old-page
HTTP/1.1 301 Moved Permanently
...

if you see 301 Moved Permanently, your redirect is working properly.