Skip to main content

Using URL Rewriting (mod_rewrite)

1. Enabling RewriteEngine

Directive Values Description
RewriteEngine on | off Enables or disables the rewrite engine. Must be set to on to use any rewrite rules.

Example: Enable URL rewriting

RewriteEngine on
Note: The RewriteEngine directive must be placed in the server config, virtual host, or .htaccess file to take effect.

2. Creating RewriteRule Directives

Directive Parameters Description
RewriteRule pattern replacement [flags] Defines a rule for rewriting URLs. The pattern is matched against the URL path, and the replacement is used to construct the new URL.

Example: Basic RewriteRule

RewriteRule ^old-page\.html$ /new-page.html [R=301,L]

Example: RewriteRule with Flags

RewriteRule ^products/([0-9]+)$ /product.php?id=$1 [QSA,L]
Note: The [L] flag indicates that this is the last rule to process if it matches. The [R=301] flag performs a permanent redirect.
Warning: Improper use of RewriteRule can lead to infinite loops or incorrect redirects. Always test rules in a development environment.

3. Setting RewriteCond Conditions

Condition Description Example
RewriteCond Defines a condition that must be met for the rule to apply RewriteCond %{REQUEST_URI} ^/old-path/(.*)$
RewriteCond %{REQUEST_URI} Checks the requested URI RewriteCond %{REQUEST_URI} ^/api/v[0-9]+/(.*)$
RewriteCond %{HTTP_HOST} Checks the host name RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteCond %{REQUEST_METHOD} Checks the HTTP method RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{QUERY_STRING} Checks the query string RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteCond %{ENV:variable} Checks environment variables RewriteCond %{ENV:REDIRECT_STATUS} ^$

Example: Matching Request URI

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/old-path/(.*)$
RewriteRule ^/old-path/(.*)$ /new-path/$1 [R=301,L]

Example: Matching Host Name

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]

Example: Matching Query String

RewriteEngine On
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^page\.html$ /redirect.php?id=%1 [R=301,L]
Note: The RewriteCond directive is used to set conditions that must be met for the RewriteRule to execute. These conditions can check various server variables, such as the requested URI, host name, query string, and more.

4. Understanding Rewrite Flags

Flag Description Notes
[E] Set environment variable Can be used to pass data between rewrite rules or to CGI scripts
[L] Last rule Stop processing any more rewrite rules if this one matches
[R] Redirect Perform an external redirect to the specified URL
[F] Forbidden Return a 403 Forbidden status code
[G] Go to gateway Send the request to a CGI script or other gateway
[P] Pass to proxy Send the request to a proxy server
[NS] No Substitution Do not substitute the rewritten URL
[NC] No Case Case-insensitive pattern matching
[QSA] Query String Append Append the query string from the original request to the rewritten URL
[S] Skip Skip the next N rules if this rule matches
[E=VAR:val] Environment Variable Set Set an environment variable with a specific value
[T=MIME_TYPE] Type Set the MIME type for the rewritten URL
[B] Backreference Escape backreferences in the substitution string
[N] Next Restart the rewrite process with the new URL
[D] Disable Disable the rewrite engine for this request
[H] Handler Set the handler for the rewritten URL
[PT] Pass Through Pass the rewritten URL through to the next handler
[CO] Cookie Set a cookie in the response
[E=VAR:val] Environment Variable Set Set an environment variable with a specific value
[E=VAR:val] Environment Variable Set Set an environment variable with a specific value

Example: Using [L] and [R]

RewriteRule ^old-page\.html$ /new-page.html [R,L]

Example: Using [NC] and [QSA]

RewriteRule ^/images/(.*)$ /images/$1 [NC,QSA]

5. Using Regular Expressions

Regular expressions are used in RewriteRule directives to match and capture parts of the URL. The syntax for regex patterns in mod_rewrite is based on the PCRE (Perl Compatible Regular Expressions) library.

Component Description Example
Pattern Regular expression to match the URL path or query string ^/old/(.*)$
Flags Optional modifiers that affect how the rule is processed [R=301,L]

Example: Capturing Groups in RewriteRule

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^/old/(.*)$ /new/$1 [R=301,L]
</IfModule>

Regular expressions in mod_rewrite support the following special characters:

Character Description Example
^ Start of string anchor ^/path/
$ End of string anchor \.html$
. Matches any single character except newline test.*html
* Matches zero or more of the preceding character ab* matches "a", "ab", "abb", etc.
+ Matches one or more of the preceding character ab+ matches "ab", "abb", etc.
? Matches zero or one of the preceding character ab? matches "a" or "ab"
() Capturing group for backreferences (\w+) captures word characters
[] Character class matching any one of the enclosed characters [abc] matches 'a', 'b', or 'c'
| Alternation operator (OR) cat|dog matches "cat" or "dog"
Note: When using regex in RewriteRule, the pattern is matched against the URL path after any query string has been removed. To match query strings, use RewriteCond with the %{QUERY_STRING} variable.

Example: Matching Query String with Regex

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{QUERY_STRING} ^id=(\d+)$
  RewriteRule ^old-page\.html$ /new-page/%1? [R=301,L]
</IfModule>

6. Capturing Groups and Backreferences

Apache's mod_rewrite supports capturing groups and backreferences using parentheses and $N syntax, where N is the group number.

Element Description Example
Capturing Group Groups parts of a pattern using parentheses () ^/user/([^/]+)/profile$
Backreference References captured content using $N, where N is the group number $1 refers to first capturing group

Example: Using Capturing Groups in RewriteRule

 RewriteRule ^/user/([^/]+)/profile$ /user.php?username=$1 [L]

Example: Multiple Capturing Groups

 RewriteRule ^/([a-z]+)/([0-9]+)$ /category.php?lang=$1&id=$2 [L]
Note: Group numbers start at 1, not 0. $0 refers to the entire matched string.
Note: Backreferences in the substitution string are expanded at rewrite time.

7. Performing Redirects with Flags

Flag Description Usage Example
R Performs a redirect, sending the client to a new URL. R=301
R=301 Permanent redirect (HTTP 301). R=301 /new-page.html
R=302 Temporary redirect (HTTP 302). R=302 /temp-page.html
R=307 Temporary redirect (HTTP 307) - preserves HTTP method. R=307 /temp-page.html
R=308 Permanent redirect (HTTP 308) - preserves HTTP method. R=308 /new-page.html
L Stops processing rules if matched (last rule). R=301 /new.html,L
NC Case-insensitive matching. R=301 /new.html,NC
QSA Appends query string from original request to the redirect. R=301 /new.html?query=1,QSA
P Proxy the redirect to another server (requires mod_proxy). R=301 /new.html,P
F Returns a 403 Forbidden status instead of redirecting. F
G Returns a 410 Gone status instead of redirecting. G
E Sets environment variables for the redirect. R=301 /new.html,E=redirected=1

Example: Redirect with 301 and L flag

R=301 /old-page.html /new-page.html,L

Example: Redirect with QSA and NC flags

R=302 /search.php?query=1&page=1,QSA,NC
Note: The R flag can be combined with other flags using commas. For example, R=301,L or R=302,NC,QSA.
Warning: Using R=301 for temporary redirects can cause issues with search engine indexing. Use R=302 for temporary redirects.

8. Rewriting Query Strings

Directive Description Example
RewriteCond Condition to test the query string RewriteCond %{QUERY_STRING} ^id=123&name=foo$
RewriteRule Rule to rewrite the query string RewriteRule ^page\.html$ /newpage.html? [R,L]

Example: Rewrite query string to clean URL

RewriteEngine On
RewriteCond %{QUERY_STRING} ^id=([0-9]+)&name=(.*)$
RewriteRule ^page\.html$ /product/%1/?name=%2? [R,L]
Note: The ? at the end of the RewriteRule prevents the query string from being appended to the new URL.

9. Conditional Rewrites Based on Variables

Variable Description Usage Example
%{HTTP_HOST} Current host name RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
%{REQUEST_URI} Requested URI RewriteCond %{REQUEST_URI} ^/old-path/(.*)$
%{QUERY_STRING} Query string of the request RewriteCond %{QUERY_STRING} ^param=value$
%{REQUEST_METHOD} HTTP method used (GET, POST, etc.) RewriteCond %{REQUEST_METHOD} ^POST$
%{HTTP_USER_AGENT} User agent string RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*$
%{REMOTE_ADDR} Client IP address RewriteCond %{REMOTE_ADDR} ^192\.168\.1\.

Example: Redirect based on User Agent

RewriteCond %{HTTP_USER_AGENT} ^Mozilla/5\.0.*Mobile
RewriteRule ^(.*)$ /mobile/$1 [R,L]

Example: Rewrite based on Host and Query String

RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^lang=fr$
RewriteRule ^(.*)$ /fr/$1 [L]
Note: The [NC] flag makes the condition case-insensitive. The [L] flag stops processing if the condition matches.

10. Using RewriteMap for Dynamic Rewrites

The RewriteMap directive allows you to define a mapping function that can be used in rewrite rules. This is particularly useful for dynamic rewrites based on external data sources or complex logic.

Directive Description Usage
RewriteMap Defines a rewrite map function RewriteMap mapname "command"

Example: Using RewriteMap with a shell command

RewriteMap lowercase "sed 's/\(.*\)/\L\1/'"
RewriteRule ^/([A-Z]+)$ /${lowercase:$1} [R,L]
Note: The RewriteMap directive is processed before any rewrite rules and can be used in .htaccess files if AllowOverride includes RewriteMap.
Warning: Be cautious with external commands in RewriteMap as they can introduce security vulnerabilities if not properly sanitized.

Key Points

  • RewriteMap allows for dynamic content transformations.
  • It supports various map types including sed, prg, and dbm.
  • Maps can be used in rewrite rules with the syntax ${mapname:value}.

11. Debugging Rewrite Rules

Example: Enabling Rewrite Logging

<IfModule mod_rewrite.c>
    RewriteLog "/var/log/apache2/rewrite.log"
    RewriteLogLevel 3
</IfModule>
Directive Description Default Notes
RewriteLog Specifies the path to the rewrite log file None Must be set with RewriteLogLevel
RewriteLogLevel Controls the verbosity of rewrite logging (0-9) 0 Higher numbers provide more detail
Note: Rewrite logging can significantly impact performance and should only be enabled during debugging.

Debugging Levels Comparison

  • Level 0: No logging
  • Level 1: Basic rule matching info
  • Level 2: Includes condition checks
  • Level 3: Full rule and condition trace
  • Level 4-9: Verbose debugging with internal processing details

Debugging Workflow

  1. Enable RewriteLog and set appropriate RewriteLogLevel
  2. Reproduce the issue or desired behavior
  3. Check the log file for rule execution details
  4. Adjust rules based on logged information
  5. Disable logging to avoid performance impact

12. Implementing Common Rewrite Patterns

Pattern Description Example Notes
^/old-page\.html$ Redirects a specific old page to a new location RewriteRule ^/old-page\.html$ /new-page.html [R=301,L] Use R=301 for permanent redirects
^/category/(.*)$ Redirects category URLs to a new structure RewriteRule ^/category/(.*)$ /blog/category/$1 [R=301,L] Matches any content after /category/
^/product/([0-9]+)$ Redirects numeric product IDs to a new format RewriteRule ^/product/([0-9]+)$ /item/$1 [R=301,L] Uses capture groups to preserve ID
^/user/(.*)$ Redirects user profile URLs to a new format RewriteRule ^/user/(.*)$ /profile/$1 [R=301,L] Redirects all user paths to a new structure
^/blog/(.*)$ Redirects blog URLs to a new format RewriteRule ^/blog/(.*)$ /articles/$1 [R=301,L] Redirects all blog paths to a new directory

Example: Redirecting Old Pages to New Locations

RewriteEngine On
RewriteRule ^/old-page\.html$ /new-page.html [R=301,L]
RewriteRule ^/old-blog\.html$ /blog/index.html [R=301,L]

Example: Redirecting Category URLs

RewriteEngine On
RewriteRule ^/category/(.*)$ /blog/category/$1 [R=301,L]

Example: Redirecting Numeric Product IDs

RewriteEngine On
RewriteRule ^/product/([0-9]+)$ /item/$1 [R=301,L]

Was this article helpful?