About
URL rewrite in Apache is done through the rewrite module.
The rules are set in the htaccess file
This module operates on the full URLs (including the path-info part) both:
- in per-server context (httpd.conf)
- and/or per-directory context (.htaccess)
Rewriting
Virtual Hosts
By default, mod_rewrite configuration settings from the main server context are not inherited by virtual hosts. To make the main server settings apply to virtual hosts, you must place the following directives in each <VirtualHost> section:
RewriteEngine On
RewriteOptions Inherit
context
- per-directory: In a <Directory> block or in a .htaccess file
Order of execution of the ruleset
mod_rewrite evaluates the left-hand-side of the RewriteRule before it evaluates the RewriteCond directives.
RewriteCond $1.php -f
RewriteCond $1.html !-f
RewriteRule ^(.*).html$ $1.php
Consequently, $1 is already defined by the time the RewriteCond directives are evaluated. This allows us to test for the existence of the original (document.html) and target (document.php) files using the same base filename.
Directive
RewriteBase
- Definition: Sets the base URL for per-directory rewrites
- Context: directory, htaccess
RewriteEngine On
# /abc/def is the physical path of /xyz
# let the server know that we were reached via /xyz and not
# via the physical path prefix /abc/def
RewriteBase /xyz
# now the rewriting rules
RewriteRule ^oldstuff\.html$ newstuff.html
In the above example, a request to /xyz/oldstuff.html gets correctly rewritten to the physical file /abc/def/newstuff.html.
Because the per-directory rewriting comes late in the process, the rewritten request has to be re-injected into the Apache kernel, as if it were a new request.
RewriteCond
- Definition: Defines a rule condition under which rewriting will take place
- Context:server config, virtual host, directory, .htaccess
Syntax:
RewriteCond TestString CondPattern [Flags]
where:
- TestString is the string to test (Server-Variables,…)
- CondPattern is a perl compatible regular expression or special system pattern expression
You can prefix the pattern string with a '!' character (exclamation mark) to specify a non-matching pattern.
- flags is a comma-separated list of flag:
Special Pattern Expression
Special pattern expression | Short Description | Description |
---|---|---|
'<CondPattern' | lexicographically precedes | Treats the CondPattern as a plain string and compares it lexicographically to TestString. True if TestString lexicographically precedes CondPattern. |
'>CondPattern' | lexicographically follows | Treats the CondPattern as a plain string and compares it lexicographically to TestString. True if TestString lexicographically follows CondPattern. |
'=CondPattern' | lexicographically equal | Treats the CondPattern as a plain string and compares it lexicographically to TestString. True if TestString is lexicographically equal to CondPattern (the two strings are exactly equal, character for character). If CondPattern is “” (two quotation marks) this compares TestString to the empty string. |
'-d' | is directory | Treats the TestString as a pathname and tests whether or not it exists, and is a directory. |
'-f' | is regular file | Treats the TestString as a pathname and tests whether or not it exists, and is a regular file. |
'-s' | is regular file, with size | Treats the TestString as a pathname and tests whether or not it exists, and is a regular file with size greater than zero. |
'-l' | is symbolic link | Treats the TestString as a pathname and tests whether or not it exists, and is a symbolic link. |
'-x' | has executable permissions | Treats the TestString as a pathname and tests whether or not it exists, and has executable permissions. These permissions are determined according to the underlying OS. |
'-F' | is existing file, via sub-request | Checks whether or not TestString is a valid file, accessible via all the server's currently-configured access controls for that path. This uses an internal subrequest to do the check, so use it with care - it can impact your server's performance! |
'-U' | is existing URL, via subrequest | Checks whether or not TestString is a valid URL, accessible via all the server's currently-configured access controls for that path. This uses an internal subrequest to do the check, so use it with care - it can impact your server's performance! |
Flag
You can add special flags after CondPattern by appending [flags] as the third argument. flags is a comma-separated list of any of the following flags:
Flages | Short Description | Description |
---|---|---|
'nocase|NC' | test case-insensitive | This makes the test case-insensitive - differences between 'A-Z' and 'a-z' are ignored, both in the expanded TestString and the CondPattern. This flag is effective only for comparisons between TestString and CondPattern. It has no effect on filesystem and subrequest checks. |
'ornext|OR' | OR Operator | Use this to combine rule conditions with a local OR instead of the implicit AND. |
'novary|NV' | no vary | If a HTTP header is used in the condition, this flag prevents this header from being added to the Vary header of the response. Using this flag might break proper caching of the response if the representation of this response varies on the value of this header. So this flag should be only used if the meaning of the Vary header is well understood. |
Example:
RewriteCond %{REMOTE_HOST} =host1 [OR]
RewriteCond %{REMOTE_HOST} =host2 [OR]
RewriteCond %{REMOTE_HOST} =host3
RewriteRule ...some special stuff for any of these hosts...
Example
- User-Agent
To rewrite the Homepage of a site according to the User-Agent: header of the request, you can use the following:
RewriteCond %{HTTP_USER_AGENT} ^Mozilla
RewriteRule ^/$ /homepage.mozilla.html [L]
RewriteCond %{HTTP_USER_AGENT} ^Lynx
RewriteRule ^/$ /homepage.lynx.html [L]
RewriteRule ^/$ /homepage.standard.html [L]
- Condition based on path
<VirtualHost *:80>
RewriteEngine On
# Rewrite everything except the blog
RewriteCond %{REQUEST_URI} !^/blog
</VirtualHost>
RewriteRule
- Description: Defines rules for the rewriting engine
- Context: server config, virtual host, directory, .htaccess
The RewriteRule directive is the real rewriting workhorse. The directive can occur more than once, with each instance defining a single rewrite rule. The order in which these rules are defined is important - this is the order in which they will be applied at run-time.
Syntax
RewriteRule Pattern Substitution [flags]
where:
- Pattern is a perl compatible regular expression that applies to the last part of the URL (ie path / query fragment, not authority)
- flags are optional flag that changes the rewrite behavior. Example: [L] where L stands for last and means “Stop the rewriting process immediately and don't apply any more rules.”
What is matched?
The Pattern will be matched
- In VirtualHost context: initially against the part of the URL after the hostname and port, and before the query string, e.g.
- /app1/index.html.
- In Directory and htaccess context: against the filesystem path, after removing the prefix that lead the server to the current RewriteRule e.g.:
- app1/index.html with an .htaccess in the root
- or index.html with an .htaccess in app1
If you wish to match against the hostname, port, or query string, use a RewriteCond with the
- %{HTTP_HOST},
- %{SERVER_PORT},
- or %{QUERY_STRING} variables respectively.
RewriteLog
- Definition: Sets the name of the file used for logging rewrite engine processing
- Context: server config, virtual host
Syntax:
RewriteLog file-path