1. Basic
    1. Load & activate mod_rewrite
    2. Enable mod_rewrite support inside .htaccess files
    3. Rewrite Condition
    4. Supported conditions
    5. Flags
    6. Magical values
    7. Rewrite Rule
    8. Rewrite context
    9. Supported flags
  2. Server Variables
    1. Request
    2. HTTP Headers
    3. Time
    4. Misc
  3. Redirect
    1. Files and directory
    2. Redirect (sub)domains
  4. Url mapping
  5. Handling query strings
  6. Security
    1. Authorization
      1. Deny access by IP
      2. Prevent image hotlinking
    2. Protocols
      1. Ensure HTTPS
  7. Example rule
    1. Query String
    2. Header check
      1. HTTP
      2. Using SSL
    3. Check the direction.

mod_rewrite is a Apache webserver module for flexible url rewriting. It is part of the standard Apache installation on all platforms.

Basic

Load & activate mod_rewrite

LoadModule mod_rewrite.so
RewriteEngine On

Enable mod_rewrite support inside .htaccess files

By default usage of mod_rewrite inside .htaccess files is not allowed. To allow usage add the following lines to the webroot Directory block inside your httpd.conf.

AllowOverride FileInfo

// will also work
AllowOverride All

Rewrite Condition

mod_rewrite Conditions are constructed as followed:

RewriteCond <test-string> <condition> [<flags>]

Supported conditions

operator meaning
< less than
> more than
= equal
-d check if path is an existing directory
-f check if path is an existing file
-s check if path is an existing file larger than 0 bytes
-l check if path is an symbolic link
-F check if path is an existing file and user is authorized to access it
-U checks if test string is a valid url and user is authorized to access it

Flags

flag meaning
NC / nocase case-insensitive matching (default: case-sensitive)
OR / ornext combine conditions via logical or (default: logical and)

Magical values

placeholder meaning
$1 .. $9 buffered values from current rewrite directive
%1 .. %9 buffered values from last rewrite condition.

Rewrite Rule

RewriteRule <original-path-regexp> <rewritten-path> [<flags>]

<original-path-regexp> is a perl regular expression (PCRE). PCRE delimiter (e.g. /) are omitted. <original-path-regexp> can be negated by prefixing it with !

<rewritten-path> can contain matches from <original-path-regexp>. Rewrite dependents on context.

Rewrite context

context rewrite
main configuration whole url is rewritten
inside block or .htaccess only the path from the current directory is rewritten.

Supported flags

Insinde RewriteRule mod_rewrite supports the following flags:

operator meaning
chain / C group rewrite rules in a chain. later rules are executed, only if the previous ones are matching
cookie=::[:[:] / CO= set a cookie based on the given data.
env=: / E=VAR:VAL set environment variable variable to value
forbidden / F send HTTP status header FORBIDDEN (403) immediately
gone / G send HTTP status header GONE (410)
last / L stop processing rewrite rules after this one
next / N abort current rewrite directive and restart rewriting
nocase / NC perfom case-insensitive matching
noescape / NE disable automatic url-encoding
nosubreq / NS  
redirect / R[=301/302/303] perform a HTTP redirect to destination and send HTTP status header (default: 302)
passthrough / PT only needed in complexe scenarios where you use multiple url rewrite engines like mod_rewrite and mod_alias together.
proxy / P a requests to the given url is performed by Apache’s module mod_proxy
qsappend / QSA append parameters to current query string
skip=[1,2,3,..,n] / S=[1,2,3,..,n] skip the next n rewrite directives
type= / T= specify mime type for request

Server Variables

Server variables are handy for writing complex mod_rewrite rules sets. The following are available inside mod_rewrite.

Request

%{REMOTE_ADDR}
%{REMOTE_HOST}
%{REMOTE_USER}
%{REMOTE_IDENT}
%{REQUEST_METHOD}
%{SCRIPT_FILENAME}
%{PATH_INFO}
%{QUERY_STRING}
%{AUTH_TYPE}

HTTP Headers

%{DOCUMENT_ROOT}
%{SERVER_ADMIN}
%{SERVER_NAME}
%{SERVER_ADDR}
%{SERVER_PORT}
%{SERVER_PROTOCOL}
%{SERVER_SOFTWARE}

Time

%{TIME_YEAR}
%{TIME_MON}
%{TIME_DAY}
%{TIME_HOUR}
%{TIME_MIN}
%{TIME_SEC}
%{TIME_WDAY}
%{TIME}

Misc

%{API_VERSION}
%{THE_REQUEST}
%{REQUEST_URI}
%{REQUEST_FILENAME}
%{IS_SUBREQ}

Redirect

Files and directory

// single url
RewriteRule ^moved-file.html$ destination-file.html [R=302,NC]

// whole directory
RewriteRule ^moved-dir(/.*)?$ destination-dir$1 [R=302,NC]

// Redirect to directories with trailing slash
RewriteCond $1 !/$
RewriteCond %{REQUEST_FILENAME}/ -d
RewriteRule (.+) http://www.example.com/$1/ [R=301,L]

// Redirect file extensions
RewriteBase /
// redirect (old) calls to php scripts to html file extension
RewriteRule ^(.*)\.php $1.html [R=301,L]
// interal map html extension to php extension
RewriteRule ^(.*)\.html $1.php [L]

Redirect (sub)domains

// Permanent redirect (301) to new domain
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.olddomain\.com$ [NC]
RewriteRule ^(.*)$ http://www.newdomain.com/$1 [R=301,L]

// Permanent redirect (301) to www.*
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301]

// Permanent redirect (301) to domain without www
RewriteCond %{HTTP_HOST} ^example.com$
RewriteRule (.*) http://www.example.com$1 [R=301]

Url mapping

// map single url
RewriteRule ^the-best-mod-rewrite-cheatsheet$ cheatsheet.html [L]

// map all urls that consist of alphanumeric to frontcontroller (index.php)
RewriteRule ^([a-z0-9-]+)/? index.php?page=$1 [NC,L]

// Path without file extensions
RewriteCond %{REQUEST_FILENAME}.php -f  
RewriteRule ^/?([a-z0-9]+)$ $1.php [NC,L]  
RewriteCond %{REQUEST_FILENAME}.html -f  
RewriteRule ^/?([a-z0-9]+)$ $1.html [NC,L]

// Map non-existing urls
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^(.*)$ index.php?page=$1

Handling query strings

// Check if query parameter exists
RewriteCond %{QUERY_STRING} !parameter=
RewriteRule ^/?parameter\.php$ missing.php [QSA,L]

// Delete query string from request
RewriteRule ^test\.php$ test.php?

// also remove from browser's address bar
RewriteRule ^test\.php$ test.php? [R,L]

Security

Authorization

Deny access by IP

In most cases using Allow <IP> and Deny <IP> is better. However you can also control access by IP via mod_rewrite.

RewriteCond %{REMOTE_ADDR} ^205\.209\.177\.
RewriteRule .* - [F]

Prevent image hotlinking

RewriteCond %{HTTP_REFERER} !^$  
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com/ [NC]  
RewriteRule \.(gif|jpg|jpeg|png)$ - [F]

Protocols

Ensure HTTPS

// based on protocol
RewriteCond %{REQUEST_URI} ^secure_area/  
RewriteCond %{HTTPS} !on   
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

// alternative using server port
RewriteCond %{REQUEST_URI} ^secure_area/  
RewriteCond %{SERVER_PORT} !^443$ 
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

Example rule

Query String

Check for the specific query string key/value

RewriteCond %{QUERY_STRING}  (&|^)id=admin(&|$)

Header check

HTTP

RewriteEngine On
RewriteCond %{HTTP:x-custom-header} ^(value1|value2|value3)$
RewriteRule .* http://google.com [L,R]

Using SSL

LoadModule ssl_module modules/mod_ssl.so
Listen 443
<VirtualHost *:443>
   SSLEngine On
   SSLCertificateFile /etc/httpd/server.pem
   RewriteEngine On
   RewriteCond %{HTTP:x-custom-header} ^(value1|value2|value3)$
   RewriteRule .* http://google.com [L,R]
</VirtualHost>

Check the direction.

[root@localhost conf]# curl -k http://localhost
OK
[root@localhost conf]# curl -k -H 'x-profile:value1' http://localhost
...
<p>The document has moved <a href="http://google.com">here</a>.</p>

[root@localhost conf]# curl -k -H 'x-profile:abcd' http://localhost