Introduction to htaccess rewrite rules

Rewrites

The .htaccess file controls a number of ways that a website can be accessed, blocked, and redirected. It does this using a series of one or more rewrite rules. These rewrites are made possible by Apache's mod_rewrite module.

mod_rewrite provides a way to modify incoming URL requests, dynamically, based on regular expression rules. This allows you to map arbitrary URLs onto your internal URL structure in any way you like.

The basic formulation of any .htaccess rewrite rule includes setting a combination of rewrite condition (RewriteCond) tests along with a corresponding rule (RewriteRule) if the prior conditions pass. In most cases, these rules should be placed at any point after the RewriteEngine on line in the .htaccess file located in the website's docroot.

Creating a useable rule generally breaks down into three steps:

  1. Determining where the tests go
  2. Building the Conditions
  3. Executing the Rule

You may also find the following items handy:

Determining where the tests go

As noted previously, rewrite rules execute after the RewriteEngine on line in the .htaccess file. We often see customers place rewrite rules after Drupal's core rewrite rules (which route the request to be handled by Drupal). These rules will typically not be evaluated, because Drupal's default request handler rules will take precedence. If you are adding rewrite rules to Drupal, they should typically be:

Building the Conditions

The first step to rewriting a path is to create a condition which will either pass or fail. This condition will then cause the rule to process, or not. Regular expressions power each condition, and are based on a group of common variables.

In some cases where simple path redirection is required, you can skip setting a RewriteCond and a RewriteRule can be passed with a simple condition. Any other conditions, including conditions based on the HTTP_HOST, must be done through a RewriteCond line.

Syntax

RewriteRule

RewriteRule Pattern Substitution [flags] 
  • pattern - regex, matched against URL-path
  • substitution - string that replaces the matched URL-path
  • flags - optional, special actions (L, R)
  • If a rule is triggered, you typically want to handle the request and stop evaluating any other rules ([L] flag)

RewriteRule Example

RewriteRule contest http://example.com/node/123 [L,R] 

RewriteCond

RewriteCond TestString CondPattern [flags] 
  • TestString - server/env variables, HTTP_HOST, REQUEST_URI, etc.
  • CondPattern - condition, usually a regex; can use a file attribute test
  • flags - optional, special actions (NC, OR)

A RewriteCond checks the value of variables, in order. The default behavior is EQUAL TO. You can change this by using an exclamation point, like the following which will be evaluated as "X-Forwarded-Proto is NOT https":

RewriteCond %{HTTP:X-Forwarded-Proto} !https 

Adding regex to the condition makes it very powerful. For example, the following line looks for domains that do not start with www:

RewriteCond %{HTTP_HOST} !^www\. [NC] 

RewriteCond rules are parsed from top to bottom. This allows multiple conditions to be placed back to back which will evaluate by default with AND before the RewriteRule is either executed or skipped. The following rule is executed as "If the request is not over HTTPS AND the host matches example.com" If both conditions pass, the following RewriteRule is executed, if one but not the other pass this rule is skipped:


RewriteCond %{HTTPS} off 
RewriteCond %{HTTP:X-Forwarded-Proto} !https 
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Executing the Rule

A RewriteRule will be executed after each preceding condition or group of conditions has passed. If there are no conditions set prior to the RewriteRule the rule will automatically execute.

Rewrite rules also include the ability to use regex matching on the URI before it is executed. In this case, a RewriteCond is not necessary and the condition can be rolled directly into the rule.

RewriteRule takes two parameters.

  • A condition based on the request URI on which to execute the Rule.
  • If this passes, the second parameter is the rule to execute.

Variables such as %{HTTP_HOST} and %{REQUEST_URI} can be passed to the second parameter as well as matching results from the regex pattern in the condition by using $1, $2, and so on.

In the following example, this is used to redirect all requests from one directory on a site to another directory. In this instance, only URI matching is necessary, no prior RewriteCond is required. Also, the regex pattern results are used to redirect any path requested relative to the directory to the same URL in the new directory:

RewriteRule ^oldfolder(.*)$ newfolder/$1 [L,R=301] 

Variables and flags

Variables and flags perform similar, but not quite the same functions for rules and conditions. Variables generally are near the beginning of the rule, and refer to where the parts of the incoming request. Flags are generally at the end of a rule, and indicate a response to a request.

Common variables

These are some of the variables that can be used when constructing a RewriteCond and a RewriteRule:

Variable Description
%{HTTPS} Set to on if the request is served over SSL.
%{HTTP_HOST} Everything between the protocol (http:// or https://) and the request (/examplefile.txt)
%{REQUEST_URI} Everything after the server address — for example, a request to http://example.com/my/examplefile.txt sets this value as my/examplefile.txt

The following variables are specific to Acquia Cloud customers:

 

Variable Description
%{ENV:AH_Client_IP} The IP address of the visitor
%{ENV:AH_SITE_ENVIRONMENT} The Acquia hosting environment — possible values are dev, test, or prod
%{HTTP:X-Forwarded-Proto} The protocol used when the URL was requested — set to http or https

Common Flags

Flags are set between brackets at the end of a RewriteCond or RewriteRule. Multiple flags may be separated by commas. A full list of flags is available at RewriteRule Flags.

Most of the flags specifically apply to RewriteRule. Only the [NC] and [OR] flags are most commonly used with RewriteCond.

 

Flag Description
[F] The request is forbidden. This can be used with conditions, such as restricting access by IP address or environment to certain paths.
[L] If the previous conditions pass this rule is executed and no more evaluation is done. Note that if the RewriteRule redirects a user to another host the L flag is forced.
[NC] Non case-sensitive matching, commonly used in a RewriteCond where the host is evaluated. For example, mysite.com is the same as MySite.com
[P] Proxy this request. This requires the mod_proxy extension to be enabled on the server. This acts like the R flag but instead of redirecting the visitor to a new URL, this URL is served as the content for the page they requested while keeping the URL in the address bar the same as requested. This is not enabled by default on Acquia Cloud. Customers who wish to use it should open a support ticket.
[PT] Passthrough causes any file path to be treated like a URI instead.
[R] Issue a redirect code with the request. By default an R flag will issue a 302 Found (Moved Temporarily) redirection, although this may be overridden by specifying the status code to accompany the redirection. Commonly this will be set as R=301 which sends a 301 "Moved Permanently" code. This is best for SEO purposes where old documents are redirected to new URLs as it will trigger the search engine to remove the previously indexed URL and replace it with the new one.

Tools

Acquia recommends testing your rules in a non-production environment. There are some tools available to help you with pre-testing:

Drupal modules

In cases where .htaccess file level redirects are more heavy-duty than necessary, or you don't have or don't want to give server-level access, there are some Drupal modules you can use to do redirects:

Either of these may be a simpler or more efficient solution to a redirect problem, especially in cases where bootstrapping Drupal is not an issue.

Contact supportStill need assistance? Contact Acquia Support