There appear to become a decent quantity of mod_rewrite threads going swimming recently with a little of confusion over how certain facets of it work. Consequently I have put together a couple of notes on common functionality, and possibly a couple of annoying nuances.

The other features / common issues perhaps you have stumble upon using mod_rewrite?

Where you can place mod_rewrite rules

mod_rewrite rules might be placed inside the httpd.conf file, or inside the .htaccess file. if you can get httpd.conf, placing rules here will offer you a performance benefit (because the rules are processed once, instead of every time the .htaccess file is known as).

Logging mod_rewrite demands

logging might be enabled from inside the httpd.conf file (including <Virtual Host>):

# logs can not be enabled from .htaccess

# loglevel > 2 is actually spammy!

RewriteLog /path/to/rewrite.log

RewriteLogLevel 2

Common use cases

  1. to funnel all demands to some single point:

    RewriteEngine on
    RewriteCond % !-f   # ignore existing files
    RewriteCond % !-d   # ignore existing sites
    RewriteRule ^(.*)$ index.php?query=$1 # map demands to index.php and append
                                          # like a query string
  2. handling 301/302 redirects:

    RewriteEngine on
    RewriteRule ^oldpage.html$ /newpage.html [R=302]  # 302 Redirect
    RewriteRule ^oldpage2.html$ /newpage.html [R=301] # 301 Redirect

    note: exterior redirects are unconditionally 301 redirects:

    # this rule:
    RewriteRule ^somepage.html$
    # is the same as:
    RewriteRule ^somepage.html$ [R]
    # and:
    RewriteRule ^somepage.html$ [R=301]
  3. forcing SSL

    RewriteEngine on
    RewriteCond % 80
    RewriteRule ^(.*)$$1 [R,L]
  4. common flag usage:

    • [R] pressure a redirect (default 301)
    • [R=302] pressure a 302 redirect
    • [L] stop spinning process (see note below in keeping issues)
    • [NC] situation insensitive matches

    you are able to combine flags:

    RewriteRule ^olddir(.*)$ /newdir$1 [L,NC]

Common issues

  1. mixing mod_alias style redirects with mod_rewrite

    # Bad
    Redirect 302 /somepage.html
    RewriteEngine on
    RewriteRule ^(.*)$ index.php?query=$1
    # Good (use mod_rewrite for)
    RewriteEngine on
    RewriteRule ^somepage.html$ /otherpage.html [R=302,L] # 302 redirect, and prevent processing
    RewriteCond % !-f
    RewriteCond % !-d
    RewriteRule ^(.*)$ index.php?query=$1                 # handle other redirects

    note: you are able to mix mod_alias with mod_rewrite, however it involves more work than simply handling fundamental redirects as above.

  2. context affects syntax

    within .htaccess files, a number one slash sits dormant within the 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
  3. [L] isn't last! (sometimes)

    inside the .htaccess context, [L] won't pressure mod_rewrite to prevent. it'll still trigger internal sub-demands:

    RewriteRule ^dirA$ /dirB [L] # processing doesn't stop here
    RewriteRule ^dirB$ /dirC     # /dirC would be the end result

    our rewrite log shows the particulars:

    rewrite 'dirA' -> '/dirB'
    internal redirect with /dirB [INTERNAL REDIRECT]
    rewrite 'dirB' -> '/dirC'

The offer with RewriteBase:

You more often than not have to set RewriteBase. If you do not, apache guesses that the is made of the physical disk road to your directory. So begin with this:

RewriteBase /

if you want to 'block' internal redirects / rewrites from happening within the .htaccess, have a look in the

RewriteCond % ^$

condition, as talked about here.