<p>There seem to be a decent number of <code>mod_rewrite</code> threads floating around lately with a bit of confusion over how certain aspects of it work. As a result I've compiled a few notes on common functionality, and perhaps a few annoying nuances.</p>

<p>What other features / common issues have you run across using <code>mod_rewrite</code>?</p>

Where to place mod_rewrite rules
```
mod_rewrite
```
rules may be placed within the
```
httpd.conf
```
file, or within the
```
.htaccess
```
file. if you have access to
```
httpd.conf
```
, placing rules here will offer a performance benefit (as the rules are processed once, as opposed to each time the
```
.htaccess
```
file is called).
Logging mod_rewrite requests
Logging may be enabled from within the
```
httpd.conf
```
file (including
```
<Virtual Host>
```
):
```
```
# logs can't be enabled from .htaccess
# loglevel > 2 is really spammy!
RewriteLog /path/to/rewrite.log
RewriteLogLevel 2
```
```
Common use cases
To funnel all requests to a single point:
```
```
RewriteEngine on
# ignore existing files
RewriteCond %{REQUEST_FILENAME} !-f   
# ignore existing directories
RewriteCond %{REQUEST_FILENAME} !-d   
# map requests to index.php and append as a query string
RewriteRule ^(.*)$ index.php?query=$1
```
```
Since Apache 2.2.16 you can also use
```
FallbackResource
```
.
Handling 301/302 redirects:
```
```
RewriteEngine on
# 302 Temporary Redirect (302 is the default, but can be specified for clarity)
RewriteRule ^oldpage\.html$ /newpage.html [R=302]  
# 301 Permanent Redirect
RewriteRule ^oldpage2\.html$ /newpage.html [R=301]
```
```
Note
: external redirects are implicitly 302 redirects:
```
```
# this rule:
RewriteRule ^somepage\.html$ http://google.com
# is equivalent to:
RewriteRule ^somepage\.html$ http://google.com [R]
# and:
RewriteRule ^somepage\.html$ http://google.com [R=302]
```
```
Forcing SSL
```
```
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R,L]
```
```
Common flags:
```
[R]
```
or
```
[redirect]
```
- force a redirect (defaults to a 302 temporary redirect)
```
[R=301]
```
or
```
[redirect=301]
```
- force a 301 permanent redirect
```
[L]
```
or
```
[last]
```
- stop rewriting process (see note below in common pitfalls)
```
[NC]
```
or
```
[nocase]
```
- specify that matching should be case insensitive
Using the long-form of flags is often more readable and will help others who come to read your code later.
You can separate multiple flags with a comma:
```
```
RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]
```
```
Common pitfalls
Mixing
```
mod_alias
```
style redirects with
```
mod_rewrite
```
```
```
# Bad
Redirect 302 /somepage.html http://example.com/otherpage.html
RewriteEngine on
RewriteRule ^(.*)$ index.php?query=$1

# Good (use mod_rewrite for both)
RewriteEngine on
# 302 redirect and stop processing
RewriteRule ^somepage.html$ /otherpage.html [R=302,L] 
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# handle other redirects
RewriteRule ^(.*)$ index.php?query=$1
```
```
Note
: you can mix
```
mod_alias
```
with
```
mod_rewrite
```
, but it involves more work than just handling basic redirects as above.
Context affects syntax
Within
```
.htaccess
```
files, a leading slash is not used in the RewriteRule pattern:
```
```
# given: GET /directory/file.html

# .htaccess
# result: /newdirectory/file.html
RewriteRule ^directory(.*)$ /newdirectory$1

# .htaccess
# result: no match!
RewriteRule ^/directory(.*)$ /newdirectory$1

# httpd.conf
# result: /newdirectory/file.html
RewriteRule ^/directory(.*)$ /newdirectory$1

# Putting a "?" after the slash will allow it to work in both contexts:
RewriteRule ^/?directory(.*)$ /newdirectory$1
```
```
[L] is not last! (sometimes)
The
```
[L]
```
flag stops processing any further rewrite rules
for that pass through the rule set
. However, if the URL was modified in that pass and you're in the
```
.htaccess
```
context or the
```
<Directory>
```
section, then your modified request is going to be passed back through the URL parsing engine again. And on the next pass, it may match a different rule this time. If you don't understand this, it often looks like your
```
[L]
```
flag had no effect.
```
```
# processing does not stop here
RewriteRule ^dirA$ /dirB [L] 
# /dirC will be the final result
RewriteRule ^dirB$ /dirC
```
```
Our rewrite log shows that the rules are run twice and the URL is updated twice:
```
```
rewrite 'dirA' -> '/dirB'
internal redirect with /dirB [INTERNAL REDIRECT]
rewrite 'dirB' -> '/dirC'
```
```
The best way around this is to use the
```
[END]
```
flag (
see Apache docs
) instead of the
```
[L]
```
flag, if you truly want to stop all further processing of rules (and subsequent passes). However, the
```
[END]
```
flag is only available for
Apache v2.3.9+
, so if you have v2.2 or lower, you're stuck with just the
```
[L]
```
flag.
For earlier versions, you must rely on
```
RewriteCond
```
statements to prevent matching of rules on subsequent passes of the URL parsing engine.
```
```
# Only process the following RewriteRule if on the first pass
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ...
```
```
Or you must ensure that your RewriteRule's are in a context (i.e.
```
httpd.conf
```
) that will not cause your request to be re-parsed.