Diskussion:Mod rewrite/TMP

Aus Foxwiki
Version vom 3. Mai 2024, 19:13 Uhr von Dirkwagner (Diskussion | Beiträge) (→‎TMP)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Apache - mod_rewrite

mod_rewrite bietet eine Möglichkeit, eingehende URL-Anfragen dynamisch anhand von Regeln für reguläre Ausdrücke zu modifizieren.

  • Dies erlaubt es Ihnen, beliebige URLs auf Ihre interne URL-Struktur abzubilden.

Es unterstützt eine unbegrenzte Anzahl von Regeln und eine unbegrenzte Anzahl von angehängten Regelbedingungen für jede Regel, um einen wirklich flexiblen und mächtigen URL-Manipulationsmechanismus zu bieten.

  • Die URL-Manipulationen können von verschiedenen Tests abhängen: Servervariablen, Umgebungsvariablen, HTTP-Header, Zeitstempel, externe Datenbankabfragen und verschiedene andere externe Programme oder Handler können verwendet werden, um einen granularen URL-Abgleich zu erreichen.

Umschreibe-Regeln können auf die vollständigen URLs angewendet werden, einschließlich der Pfad-Informationen und der Abfrage-String-Teile, und können im Kontext pro Server (httpd.conf), pro virtuellem Host (<VirtualHost>-Blöcke) oder pro Verzeichnis (.htaccess-Dateien und <Directory>-Blöcke) verwendet werden.

  • Das umgeschriebene Ergebnis kann zu weiteren Regeln, interner Unterverarbeitung, externer Umleitung von Anfragen oder Proxy-Passthrough führen, je nachdem, welche Flags Sie den Regeln hinzufügen.

Da mod_rewrite so mächtig ist, kann es in der Tat ziemlich komplex sein.

  • Dieses Dokument ergänzt die Referenzdokumentation und versucht, einen Teil dieser Komplexität zu mildern und bietet ausführlich kommentierte Beispiele für häufige Szenarien, die Sie mit mod_rewrite behandeln können.
  • Wir versuchen aber auch, Ihnen zu zeigen, wann Sie mod_rewrite nicht verwenden und stattdessen andere Standard-Apache-Funktionen nutzen sollten, um diese unnötige Komplexität zu vermeiden.
  • Rewrite-Referenzdokumentation
  • Einführung in reguläre Ausdrücke und mod_rewrite
  • Verwendung von mod_rewrite für die Umleitung und Neuzuordnung von URLs
  • Verwendung von mod_rewrite zur Zugriffskontrolle
  • Dynamische virtuelle Hosts mit mod_rewrite
  • Dynamisches Proxying mit mod_rewrite
  • Verwendung von RewriteMap
  • Fortgeschrittene Techniken
  • Wann man mod_rewrite NICHT verwenden sollte
  • RewriteRule-Flags
  • Technische Details

Apache Module mod_rewrite

Description: Provides a rule-based rewriting engine to rewrite requested URLs on the fly
Status: Extension
Module Identifier: rewrite_module
Source File: mod_rewrite.c

Summary

The mod_rewrite module uses a rule-based rewriting engine, based on a PCRE regular-expression parser, to rewrite requested URLs on the fly. By default, mod_rewrite maps a URL to a filesystem path. However, it can also be used to redirect one URL to another URL, or to invoke an internal proxy fetch.

mod_rewrite provides a flexible and powerful way to manipulate URLs using an unlimited number of rules. Each rule can have an unlimited number of attached rule conditions, to allow you to rewrite URL based on server variables, environment variables, HTTP headers, or time stamps.

mod_rewrite operates on the full URL path, including the path-info section. A rewrite rule can be invoked in httpd.conf or in .htaccess. The path generated by a rewrite rule can include a query string, or can lead to internal sub-processing, external request redirection, or internal proxy throughput.

Further details, discussion, and examples, are provided in the detailed mod_rewrite documentation.

Topics

  • Logging

Directives

  • RewriteBase
  • RewriteCond
  • RewriteEngine
  • RewriteMap
  • RewriteOptions
  • RewriteRule

Bugfix checklist

  • httpd changelog
  • Known issues
  • Report a bug

Logging

mod_rewrite offers detailed logging of its actions at the trace1 to trace8 log levels. The log level can be set specifically for mod_rewrite using the LogLevel directive: Up to level debug, no actions are logged, while trace8 means that practically all actions are logged.

Using a high trace log level for mod_rewrite will slow down your Apache HTTP Server dramatically! Use a log level higher than trace2 only for debugging!

Example

LogLevel alert rewrite:trace3

RewriteLog

Those familiar with earlier versions of mod_rewrite will no doubt be looking for the RewriteLog and RewriteLogLevel directives. This functionality has been completely replaced by the new per-module logging configuration mentioned above.

To get just the mod_rewrite-specific log messages, pipe the log file through grep:

tail -f error_log|fgrep '[rewrite:'

RewriteBase Directive

Description: Sets the base URL for per-directory rewrites
Syntax: RewriteBase URL-path
Default: None
Context: directory, .htaccess
Override: FileInfo
Status: Extension
Module: mod_rewrite

The RewriteBase directive specifies the URL prefix to be used for per-directory (htaccess) RewriteRule directives that substitute a relative path.

This directive is required when you use a relative path in a substitution in per-directory (htaccess) context unless any of the following conditions are true:* The original request, and the substitution, are underneath the DocumentRoot (as opposed to reachable by other means, such as Alias).

  • The filesystem path to the directory containing the RewriteRule, suffixed by the relative substitution is also valid as a URL path on the server (this is rare).
  • In Apache HTTP Server 2.4.16 and later, this directive may be omitted when the request is mapped via Alias or mod_userdir.

In the example below, RewriteBase is necessary to avoid rewriting to http://example.com/opt/myapp-1.2.3/welcome.html since the resource was not relative to the document root. This misconfiguration would normally cause the server to look for an "opt" directory under the document root.

DocumentRoot "/var/www/example.com"
AliasMatch "^/myapp" "/opt/myapp-1.2.3"
<Directory "/opt/myapp-1.2.3">
 RewriteEngine On
 RewriteBase "/myapp/"
 RewriteRule "^index\.html$" "welcome.html"
</Directory>

RewriteCond Directive

Description: Defines a condition under which rewriting will take place
Syntax: RewriteCond TestString CondPattern [flags]
Context: server config, virtual host, directory, .htaccess
Override: FileInfo
Status: Extension
Module: mod_rewrite

The RewriteCond directive defines a rule condition. One or more RewriteCond can precede a RewriteRule directive. The following rule is then only used if both the current state of the URI matches its pattern, and if these conditions are met.

TestString is a string which can contain the following expanded constructs in addition to plain text:* RewriteRule backreferences: These are backreferences of the form $N (0 <= N <= 9). $1 to $9 provide access to the grouped parts (in parentheses) of the pattern, from the RewriteRule which is subject to the current set of RewriteCond conditions. $0 provides access to the whole string matched by that pattern.

  • RewriteCond backreferences: These are backreferences of the form %N (0 <= N <= 9). %1 to %9 provide access to the grouped parts (again, in parentheses) of the pattern, from the last matched RewriteCond in the current set of conditions. %0 provides access to the whole string matched by that pattern.
  • RewriteMap expansions: These are expansions of the form ${mapname:key|default}. See the documentation for RewriteMap for more details.
  • Server-Variables: These are variables of the form %{ NAME_OF_VARIABLE } where NAME_OF_VARIABLE can be a string taken from the following list:
HTTP headers: connection & request:
HTTP_ACCEPTHTTP_COOKIEHTTP_FORWARDEDHTTP_HOSTHTTP_PROXY_CONNECTIONHTTP_REFERERHTTP_USER_AGENT AUTH_TYPECONN_REMOTE_ADDRCONTEXT_PREFIXCONTEXT_DOCUMENT_ROOTIPV6PATH_INFOQUERY_STRINGREMOTE_ADDRREMOTE_HOSTREMOTE_IDENTREMOTE_PORTREMOTE_USERREQUEST_METHODSCRIPT_FILENAME
server internals: date and time: specials:
DOCUMENT_ROOTSCRIPT_GROUPSCRIPT_USERSERVER_ADDRSERVER_ADMINSERVER_NAMESERVER_PORTSERVER_PROTOCOLSERVER_SOFTWARE TIME_YEARTIME_MONTIME_DAYTIME_HOURTIME_MINTIME_SECTIME_WDAYTIME API_VERSIONCONN_REMOTE_ADDRHTTPSIS_SUBREQREMOTE_ADDRREQUEST_FILENAMEREQUEST_SCHEMEREQUEST_URITHE_REQUEST

These variables all correspond to the similarly named HTTP MIME-headers, C variables of the Apache HTTP Server or struct tm fields of the Unix system. Most are documented here or elsewhere in the Manual or in the CGI specification.

SERVER_NAME and SERVER_PORT depend on the values of UseCanonicalName and UseCanonicalPhysicalPort respectively.

Those that are special to mod_rewrite include those below.

API_VERSION

This is the version of the Apache httpd module API (the internal interface between server and module) in the current httpd build, as defined in include/ap_mmn.h. The module API version corresponds to the version of Apache httpd in use (in the release version of Apache httpd 1.3.14, for instance, it is 19990320:10), but is mainly of interest to module authors.

CONN_REMOTE_ADDR

Since 2.4.8: The peer IP address of the connection (see the mod_remoteip module).

HTTPS

Will contain the text "on" if the connection is using SSL/TLS, or "off" otherwise. (This variable can be safely used regardless of whether or not mod_ssl is loaded).

IS_SUBREQ

Will contain the text "true" if the request currently being processed is a sub-request, "false" otherwise. Sub-requests may be generated by modules that need to resolve additional files or URIs in order to complete their tasks.

REMOTE_ADDR

The IP address of the remote host (see the mod_remoteip module).

REQUEST_FILENAME

The full local filesystem path to the file or script matching the request, if this has already been determined by the server at the time REQUEST_FILENAME is referenced. Otherwise, such as when used in virtual host context, the same value as REQUEST_URI. Depending on the value of AcceptPathInfo, the server may have only used some leading components of the REQUEST_URI to map the request to a file.

REQUEST_SCHEME

Will contain the scheme of the request (usually "http" or "https"). This value can be influenced with ServerName.

REQUEST_URI

The path component of the requested URI, such as "/index.html". This notably excludes the query string which is available as its own variable named QUERY_STRING.

THE_REQUEST

The full HTTP request line sent by the browser to the server (e.g., "GET /index.html HTTP/1.1"). This does not include any additional headers sent by the browser. This value has not been unescaped (decoded), unlike most other variables below. If the TestString has the special value expr, the CondPattern will be treated as an ap_expr. HTTP headers referenced in the expression will be added to the Vary header if the novary flag is not given.

Other things you should be aware of:# The variables SCRIPT_FILENAME and REQUEST_FILENAME contain the same value - the value of the filename field of the internal request_rec structure of the Apache HTTP Server. The first name is the commonly known CGI variable name while the second is the appropriate counterpart of REQUEST_URI (which contains the value of the uri field of request_rec).
If a substitution occurred and the rewriting continues, the value of both variables will be updated accordingly.
If used in per-server context (i.e., before the request is mapped to the filesystem) SCRIPT_FILENAME and REQUEST_FILENAME cannot contain the full local filesystem path since the path is unknown at this stage of processing. Both variables will initially contain the value of REQUEST_URI in that case. In order to obtain the full local filesystem path of the request in per-server context, use an URL-based look-ahead %{LA-U:REQUEST_FILENAME} to determine the final value of REQUEST_FILENAME.

  1. %{ENV:variable}, where variable can be any environment variable, is also available. This is looked-up via internal Apache httpd structures and (if not found there) via getenv() from the Apache httpd server process.
  2. %{SSL:variable}, where variable is the name of an SSL environment variable, can be used whether or not mod_ssl is loaded, but will always expand to the empty string if it is not. Example: %{SSL:SSL_CIPHER_USEKEYSIZE} may expand to 128. These variables are available even without setting the StdEnvVars option of the SSLOptions directive.
  3. %{HTTP:header}, where header can be any HTTP MIME-header name, can always be used to obtain the value of a header sent in the HTTP request. Example: %{HTTP:Proxy-Connection} is the value of the HTTP header ``Proxy-Connection:.
    If a HTTP header is used in a condition this header is added to the Vary header of the response in case the condition evaluates to true for the request. It is not added if the condition evaluates to false for the request. Adding the HTTP header to the Vary header of the response is needed for proper caching.
    It has to be kept in mind that conditions follow a short circuit logic in the case of the 'ornext|OR' flag so that certain conditions might not be evaluated at all.
  4. %{LA-U:variable} can be used for look-aheads which perform an internal (URL-based) sub-request to determine the final value of variable. This can be used to access variable for rewriting which is not available at the current stage, but will be set in a later phase.
    For instance, to rewrite according to the REMOTE_USER variable from within the per-server context (httpd.conf file) you must use %{LA-U:REMOTE_USER} - this variable is set by the authorization phases, which come after the URL translation phase (during which mod_rewrite operates).
    On the other hand, because mod_rewrite implements its per-directory context (.htaccess file) via the Fixup phase of the API and because the authorization phases come before this phase, you just can use %{REMOTE_USER} in that context.
  5. %{LA-F:variable} can be used to perform an internal (filename-based) sub-request, to determine the final value of variable. Most of the time, this is the same as LA-U above.

CondPattern is the condition pattern, a regular expression which is applied to the current instance of the TestString. TestString is first evaluated, before being matched against CondPattern.

CondPattern is usually a perl compatible regular expression, but there is additional syntax available to perform other useful tests against the Teststring:# You can prefix the pattern string with a '!' character (exclamation mark) to negate the result of the condition, no matter what kind of CondPattern is used.

  1. You can perform lexicographical string comparisons:
    <CondPattern
    Lexicographically precedesTreats the CondPattern as a plain string and compares it lexicographically to TestString. True if TestString lexicographically precedes CondPattern.
    >CondPattern
    Lexicographically followsTreats the CondPattern as a plain string and compares it lexicographically to TestString. True if TestString lexicographically follows CondPattern.
    =CondPattern
    Lexicographically equalTreats 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.
    <=CondPattern
    Lexicographically less than or equal toTreats the CondPattern as a plain string and compares it lexicographically to TestString. True if TestString lexicographically precedes CondPattern, or is equal to CondPattern (the two strings are equal, character for character).
    >=CondPattern
    Lexicographically greater than or equal toTreats the CondPattern as a plain string and compares it lexicographically to TestString. True if TestString lexicographically follows CondPattern, or is equal to CondPattern (the two strings are equal, character for character).
  2. You can perform integer comparisons:
    -eq
    Is numerically equal toThe TestString is treated as an integer, and is numerically compared to the CondPattern. True if the two are numerically equal.
    -ge
    Is numerically greater than or equal toThe TestString is treated as an integer, and is numerically compared to the CondPattern. True if the TestString is numerically greater than or equal to the CondPattern.
    -gt
    Is numerically greater thanThe TestString is treated as an integer, and is numerically compared to the CondPattern. True if the TestString is numerically greater than the CondPattern.
    -le
    Is numerically less than or equal toThe TestString is treated as an integer, and is numerically compared to the CondPattern. True if the TestString is numerically less than or equal to the CondPattern. Avoid confusion with the -l by using the -L or -h variant.
    -lt
    Is numerically less thanThe TestString is treated as an integer, and is numerically compared to the CondPattern. True if the TestString is numerically less than the CondPattern. Avoid confusion with the -l by using the -L or -h variant.
    -ne
    Is numerically not equal toThe TestString is treated as an integer, and is numerically compared to the CondPattern. True if the two are numerically different. This is equivalent to !-eq.
  3. You can perform various file attribute tests:
    -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.
    -F
    Is existing file, via subrequest.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!
    -h
    Is symbolic link, bash convention.See -l.
    -l
    Is symbolic link.Treats the TestString as a pathname and tests whether or not it exists, and is a symbolic link. May also use the bash convention of -L or -h if there's a possibility of confusion such as when using the -lt or -le tests.
    -L
    Is symbolic link, bash convention.See -l.
    -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.
    -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!
    This flag only returns information about things like access control, authentication, and authorization. This flag does not return information about the status code the configured handler (static file, CGI, proxy, etc.) would have returned.
    -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.
    For example:
    RewriteCond /var/www/%{REQUEST_URI} !-f
    RewriteRule ^(.+) /other/archive/$1 [R]
  4. If the TestString has the special value expr, the CondPattern will be treated as an ap_expr.
    In the below example, -strmatch is used to compare the REFERER against the site hostname, to block unwanted hotlinking.
    RewriteCond expr "! %{HTTP_REFERER} -strmatch '*://%{HTTP_HOST}/*'"
    RewriteRule "^/images" "-" [F]

You can also set special flags for CondPattern by appending [flags] as the third argument to the RewriteCond directive, where flags is a comma-separated list of any of the following flags:* 'nocase|NC' (no case)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 next condition)Use this to combine rule conditions with a local OR instead of the implicit AND. Typical example:
    RewriteCond "%{REMOTE_HOST}" "^host1" [OR]
    RewriteCond "%{REMOTE_HOST}" "^host2" [OR]
    RewriteCond "%{REMOTE_HOST}" "^host3"
    RewriteRule ...some special stuff for any of these hosts...
    Without this flag you would have to write the condition/rule pair three times.
  • '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:

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}" "(iPhone|Blackberry|Android)" RewriteRule "^/$" "/homepage.mobile.html" [L]

RewriteRule "^/$" "/homepage.std.html" [L]

Explanation: If you use a browser which identifies itself as a mobile browser (note that the example is incomplete, as there are many other mobile platforms), the mobile version of the homepage is served. Otherwise, the standard page is served.

RewriteEngine Directive

Description: Enables or disables runtime rewriting engine
Syntax: RewriteEngine on|off
Default: RewriteEngine off
Context: server config, virtual host, directory, .htaccess
Override: FileInfo
Status: Extension
Module: mod_rewrite

The RewriteEngine directive enables or disables the runtime rewriting engine. If it is set to off this module does no runtime processing at all. It does not even update the SCRIPT_URx environment variables.

Use this directive to disable rules in a particular context, rather than commenting out all the RewriteRule directives.

Note that rewrite configurations are not inherited by virtual hosts. This means that you need to have a RewriteEngine on directive for each virtual host in which you wish to use rewrite rules.

RewriteMap directives of the type prg are not started during server initialization if they're defined in a context that does not have RewriteEngine set to on

RewriteMap Directive

Description: Defines a mapping function for key-lookup
Syntax: RewriteMap MapName MapType:MapSource
Context: server config, virtual host
Status: Extension
Module: mod_rewrite

The RewriteMap directive defines a Rewriting Map which can be used inside rule substitution strings by the mapping-functions to insert/substitute fields through a key lookup. The source of this lookup can be of various types.

The MapName is the name of the map and will be used to specify a mapping-function for the substitution strings of a rewriting rule via one of the following constructs:

${ MapName : LookupKey }${ MapName : LookupKey | DefaultValue }

When such a construct occurs, the map MapName is consulted and the key LookupKey is looked-up. If the key is found, the map-function construct is substituted by SubstValue. If the key is not found then it is substituted by DefaultValue or by the empty string if no DefaultValue was specified. Empty values behave as if the key was absent, therefore it is not possible to distinguish between empty-valued keys and absent keys.

For example, you might define a RewriteMap as:

RewriteMap examplemap "txt:/path/to/file/map.txt"

You would then be able to use this map in a RewriteRule as follows:

RewriteRule "^/ex/(.*)" "${examplemap:$1}"

The following combinations for MapType and MapSource can be used:

txt
A plain text file containing space-separated key-value pairs, one per line. (Details ...)
rnd
Randomly selects an entry from a plain text file (Details ...)
dbm
Looks up an entry in a dbm file containing name, value pairs. Hash is constructed from a plain text file format using the httxt2dbm utility. (Details ...)
int
One of the four available internal functions provided by RewriteMap: toupper, tolower, escape or unescape. (Details ...)
prg
Calls an external program or script to process the rewriting. (Details ...)

dbd or fastdbd

A SQL SELECT statement to be performed to look up the rewrite target. (Details ...)

Further details, and numerous examples, may be found in the RewriteMap HowTo

RewriteOptions Directive

Description: Sets some special options for the rewrite engine
Syntax: RewriteOptions Options
Context: server config, virtual host, directory, .htaccess
Override: FileInfo
Status: Extension
Module: mod_rewrite

The RewriteOptions directive sets some special options for the current per-server or per-directory configuration. The Option string can currently only be one of the following:

Inherit
This forces the current configuration to inherit the configuration of the parent. In per-virtual-server context, this means that the maps, conditions and rules of the main server are inherited. In per-directory context this means that conditions and rules of the parent directory's .htaccess configuration or <Directory> sections are inherited. The inherited rules are virtually copied to the section where this directive is being used. If used in combination with local rules, the inherited rules are copied behind the local rules. The position of this directive - below or above of local rules - has no influence on this behavior. If local rules forced the rewriting to stop, the inherited rules won't be processed.
Rules inherited from the parent scope are applied after rules specified in the child scope.
InheritBefore
Like Inherit above, but the rules from the parent scope are applied before rules specified in the child scope.Available in Apache HTTP Server 2.3.10 and later.
InheritDown
If this option is enabled, all child configurations will inherit the configuration of the current configuration. It is equivalent to specifying RewriteOptions Inherit in all child configurations. See the Inherit option for more details on how the parent-child relationships are handled.Available in Apache HTTP Server 2.4.8 and later.
InheritDownBefore
Like InheritDown above, but the rules from the current scope are applied before rules specified in any child's scope.Available in Apache HTTP Server 2.4.8 and later.
IgnoreInherit
This option forces the current and child configurations to ignore all rules that would be inherited from a parent specifying InheritDown or InheritDownBefore.Available in Apache HTTP Server 2.4.8 and later.
AllowNoSlash
By default, mod_rewrite will ignore URLs that map to a directory on disk but lack a trailing slash, in the expectation that the mod_dir module will issue the client with a redirect to the canonical URL with a trailing slash.
When the DirectorySlash directive is set to off, the AllowNoSlash option can be enabled to ensure that rewrite rules are no longer ignored. This option makes it possible to apply rewrite rules within .htaccess files that match the directory without a trailing slash, if so desired.Available in Apache HTTP Server 2.4.0 and later.
AllowAnyURI
When RewriteRule is used in VirtualHost or server context with version 2.2.22 or later of httpd, mod_rewrite will only process the rewrite rules if the request URI is a URL-path. This avoids some security issues where particular rules could allow "surprising" pattern expansions (see CVE-2011-3368 and CVE-2011-4317). To lift the restriction on matching a URL-path, the AllowAnyURI option can be enabled, and mod_rewrite will apply the rule set to any request URI string, regardless of whether that string matches the URL-path grammar required by the HTTP specification.Available in Apache HTTP Server 2.4.3 and later.

Security Warning

Enabling this option will make the server vulnerable to security issues if used with rewrite rules which are not carefully authored. It is strongly recommended that this option is not used. In particular, beware of input strings containing the '@' character which could change the interpretation of the transformed URI, as per the above CVE names.
MergeBase
With this option, the value of RewriteBase is copied from where it's explicitly defined into any sub-directory or sub-location that doesn't define its own RewriteBase. This was the default behavior in 2.4.0 through 2.4.3, and the flag to restore it is available Apache HTTP Server 2.4.4 and later.
IgnoreContextInfo
When a relative substitution is made in directory (htaccess) context and RewriteBase has not been set, this module uses some extended URL and filesystem context information to change the relative substitution back into a URL. Modules such as mod_userdir and mod_alias supply this extended context info. Available in 2.4.16 and later.
LegacyPrefixDocRoot
Prior to 2.4.26, if a substitution was an absolute URL that matched the current virtual host, the URL might first be reduced to a URL-path and then later reduced to a local path. Since the URL can be reduced to a local path, the path should be prefixed with the document root. This prevents a file such as /tmp/myfile from being accessed when a request is made to http://host/file/myfile with the following RewriteRule.

RewriteRule /file/(.*) http://localhost/tmp/$1

This option allows the old behavior to be used where the document root is not prefixed to a local path that was reduced from a URL. Available in 2.4.26 and later.

RewriteRule Directive

Description: Defines rules for the rewriting engine
Syntax: RewriteRule Pattern Substitution [flags]
Context: server config, virtual host, directory, .htaccess
Override: FileInfo
Status: Extension
Module: mod_rewrite

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.

Pattern is a perl compatible regular expression. What this pattern is compared against varies depending on where the RewriteRule directive is defined.

What is matched?

  • In VirtualHost context, The Pattern will initially be matched against the part of the URL after the hostname and port, and before the query string (e.g. "/app1/index.html"). This is the (%-decoded) URL-path.
  • In per-directory context (Directory and .htaccess), the Pattern is matched against only a partial path, for example a request of "/app1/index.html" may result in comparison against "app1/index.html" or "index.html" depending on where the RewriteRule is defined.
  • The directory path where the rule is defined is stripped from the currently mapped filesystem path before comparison (up to and including a trailing slash). The net result of this per-directory prefix stripping is that rules in this context only match against the portion of the currently mapped filesystem path "below" where the rule is defined.
  • Directives such as DocumentRoot and Alias, or even the result of previous RewriteRule substitutions, determine the currently mapped filesystem path.
  • 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.

Per-directory Rewrites

  • The rewrite engine may be used in .htaccess files and in <Directory> sections, with some additional complexity.
  • To enable the rewrite engine in this context, you need to set "RewriteEngine On" and "Options FollowSymLinks" must be enabled. If your administrator has disabled override of FollowSymLinks for a user's directory, then you cannot use the rewrite engine. This restriction is required for security reasons.
  • See the RewriteBase directive for more information regarding what prefix will be added back to relative substitutions.
  • If you wish to match against the full URL-path in a per-directory (htaccess) RewriteRule, use the %{REQUEST_URI} variable in a RewriteCond.
  • The removed prefix always ends with a slash, meaning the matching occurs against a string which never has a leading slash. Therefore, a Pattern with ^/ never matches in per-directory context.
  • Although rewrite rules are syntactically permitted in <Location> and <Files> sections (including their regular expression counterparts), this should never be necessary and is unsupported. A likely feature to break in these contexts is relative substitutions.

For some hints on regular expressions, see the mod_rewrite Introduction.

In mod_rewrite, the NOT character ('!') is also available as a possible pattern prefix. This enables you to negate a pattern; to say, for instance: ``if the current URL does NOT match this pattern''. This can be used for exceptional cases, where it is easier to match the negative pattern, or as a last default rule.

Note

When using the NOT character to negate a pattern, you cannot include grouped wildcard parts in that pattern. This is because, when the pattern does NOT match (ie, the negation matches), there are no contents for the groups. Thus, if negated patterns are used, you cannot use $N in the substitution string!

The Substitution of a rewrite rule is the string that replaces the original URL-path that was matched by Pattern. The Substitution may be a:

file-system path
Designates the location on the file-system of the resource to be delivered to the client. Substitutions are only treated as a file-system path when the rule is configured in server (virtualhost) context and the first component of the path in the substitution exists in the file-system
URL-path
A DocumentRoot-relative path to the resource to be served. Note that mod_rewrite tries to guess whether you have specified a file-system path or a URL-path by checking to see if the first segment of the path exists at the root of the file-system. For example, if you specify a Substitution string of /www/file.html, then this will be treated as a URL-path unless a directory named www exists at the root or your file-system (or, in the case of using rewrites in a .htaccess file, relative to your document root), in which case it will be treated as a file-system path. If you wish other URL-mapping directives (such as Alias) to be applied to the resulting URL-path, use the [PT] flag as described below.
Absolute URL
If an absolute URL is specified, mod_rewrite checks to see whether the hostname matches the current host. If it does, the scheme and hostname are stripped out and the resulting path is treated as a URL-path. Otherwise, an external redirect is performed for the given URL. To force an external redirect back to the current host, see the [R] flag below.
- (dash)
A dash indicates that no substitution should be performed (the existing path is passed through untouched). This is used when a flag (see below) needs to be applied without changing the path.

In addition to plain text, the Substitution string can include# back-references ($N) to the RewriteRule pattern

  1. back-references (%N) to the last matched RewriteCond pattern
  2. server-variables as in rule condition test-strings (%{VARNAME})
  3. mapping-function calls (${mapname:key|default})

Back-references are identifiers of the form $N (N=0..9), which will be replaced by the contents of the Nth group of the matched Pattern. The server-variables are the same as for the TestString of a RewriteCond directive. The mapping-functions come from the RewriteMap directive and are explained there. These three types of variables are expanded in the order above.

Rewrite rules are applied to the results of previous rewrite rules, in the order in which they are defined in the config file. The URL-path or file-system path (see "What is matched?", above) is completely replaced by the Substitution and the rewriting process continues until all rules have been applied, or it is explicitly terminated by an L flag, or other flag which implies immediate termination, such as END or F.

Modifying the Query String

By default, the query string is passed through unchanged. You can, however, create URLs in the substitution string containing a query string part. Simply use a question mark inside the substitution string to indicate that the following text should be re-injected into the query string. When you want to erase an existing query string, end the substitution string with just a question mark. To combine new and old query strings, use the [QSA] flag.

Additionally you can set special actions to be performed by appending [flags] as the third argument to the RewriteRule directive. Flags is a comma-separated list, surround by square brackets, of any of the flags in the following table. More details, and examples, for each flag, are available in the Rewrite Flags document.

Flag and syntax Function
B Escape non-alphanumeric characters in backreferences before applying the transformation. details ...
backrefnoplus|BNP If backreferences are being escaped, spaces should be escaped to %20 instead of +. Useful when the backreference will be used in the path component rather than the query string.details ...
chain|C Rule is chained to the following rule. If the rule fails, the rule(s) chained to it will be skipped. details ...
cookie|CO=NAME:VAL Sets a cookie in the client browser. Full syntax is: CO=NAME:VAL:domain[:lifetime[:path[:secure[:httponly]]]] details ...
discardpath|DPI Causes the PATH_INFO portion of the rewritten URI to be discarded. details ...
END Stop the rewriting process immediately and don't apply any more rules. Also prevents further execution of rewrite rules in per-directory and .htaccess context. (Available in 2.3.9 and later) details ...
env|E=[!]VAR[:VAL] Causes an environment variable VAR to be set (to the value VAL if provided). The form !VAR causes the environment variable VAR to be unset. details ...
forbidden|F Returns a 403 FORBIDDEN response to the client browser. details ...
gone|G Returns a 410 GONE response to the client browser. details ...
Handler|H=Content-handler Causes the resulting URI to be sent to the specified Content-handler for processing. details ...
last|L Stop the rewriting process immediately and don't apply any more rules. Especially note caveats for per-directory and .htaccess context (see also the END flag). details ...
next|N Re-run the rewriting process, starting again with the first rule, using the result of the ruleset so far as a starting point. details ...
nocase|NC Makes the pattern comparison case-insensitive. details ...
noescape|NE Prevent mod_rewrite from applying hexcode escaping of special characters in the result of the rewrite. details ...
nosubreq|NS Causes a rule to be skipped if the current request is an internal sub-request. details ...
proxy|P Force the substitution URL to be internally sent as a proxy request. details ...
passthrough|PT Forces the resulting URI to be passed back to the URL mapping engine for processing of other URI-to-filename translators, such as Alias or Redirect. details ...
qsappend|QSA Appends any query string from the original request URL to any query string created in the rewrite target.details ...
qsdiscard|QSD Discard any query string attached to the incoming URI. details ...
qslast|QSL Interpret the last (right-most) question mark as the query string delimiter, instead of the first (left-most) as normally used. Available in 2.4.19 and later. details ...
redirect|R[=code] Forces an external redirect, optionally with the specified HTTP status code. details ...
skip|S=num Tells the rewriting engine to skip the next num rules if the current rule matches. details ...
type|T=MIME-type Force the MIME-type of the target file to be the specified type. details ...

Home directory expansion

When the substitution string begins with a string resembling "/~user" (via explicit text or backreferences), mod_rewrite performs home directory expansion independent of the presence or configuration of mod_userdir.

This expansion does not occur when the PT flag is used on the RewriteRule directive.

Here are all possible substitution combinations and their meanings:

Inside per-server configuration (httpd.conf)for request ``GET /somepath/pathinfo:

Given Rule Resulting Substitution
^/somepath(.*) otherpath$1 invalid, not supported
^/somepath(.*) otherpath$1 [R] invalid, not supported
^/somepath(.*) otherpath$1 [P] invalid, not supported
^/somepath(.*) /otherpath$1 /otherpath/pathinfo
^/somepath(.*) /otherpath$1 [R] http://thishost/otherpath/pathinfo via external redirection
^/somepath(.*) /otherpath$1 [P] doesn't make sense, not supported
^/somepath(.*) http://thishost/otherpath$1 /otherpath/pathinfo
^/somepath(.*) http://thishost/otherpath$1 [R] http://thishost/otherpath/pathinfo via external redirection
^/somepath(.*) http://thishost/otherpath$1 [P] doesn't make sense, not supported
^/somepath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo via external redirection
^/somepath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo via external redirection (the [R] flag is redundant)
^/somepath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo via internal proxy

Inside per-directory configuration for /somepath(/physical/path/to/somepath/.htaccess, with RewriteBase "/somepath")for request ``GET /somepath/localpath/pathinfo:

Given Rule Resulting Substitution
^localpath(.*) otherpath$1 /somepath/otherpath/pathinfo
^localpath(.*) otherpath$1 [R] http://thishost/somepath/otherpath/pathinfo via external redirection
^localpath(.*) otherpath$1 [P] doesn't make sense, not supported
^localpath(.*) /otherpath$1 /otherpath/pathinfo
^localpath(.*) /otherpath$1 [R] http://thishost/otherpath/pathinfo via external redirection
^localpath(.*) /otherpath$1 [P] doesn't make sense, not supported
^localpath(.*) http://thishost/otherpath$1 /otherpath/pathinfo
^localpath(.*) http://thishost/otherpath$1 [R] http://thishost/otherpath/pathinfo via external redirection
^localpath(.*) http://thishost/otherpath$1 [P] doesn't make sense, not supported
^localpath(.*) http://otherhost/otherpath$1 http://otherhost/otherpath/pathinfo via external redirection
^localpath(.*) http://otherhost/otherpath$1 [R] http://otherhost/otherpath/pathinfo via external redirection (the [R] flag is redundant)
^localpath(.*) http://otherhost/otherpath$1 [P] http://otherhost/otherpath/pathinfo via internal proxy

Redirecting and Remapping with mod_rewrite

This document supplements the mod_rewrite reference documentation. It describes how you can use mod_rewrite to redirect and remap request. This includes many examples of common uses of mod_rewrite, including detailed descriptions of how each works.

Note that many of these examples won't work unchanged in your particular server configuration, so it's important that you understand them, rather than merely cutting and pasting the examples into your configuration.* From Old to New (internal)

  • Rewriting From Old to New (external)
  • Resource Moved to Another Server
  • From Static to Dynamic
  • Backward Compatibility for file extension change
  • Canonical Hostnames
  • Search for pages in more than one directory
  • Redirecting to Geographically Distributed Servers
  • Browser Dependent Content
  • Canonical URLs
  • Moved DocumentRoot
  • Fallback Resource
  • Rewrite query string

See also

  • Module documentation
  • mod_rewrite introduction
  • Controlling access
  • Virtual hosts
  • Proxying
  • Using RewriteMap
  • Advanced techniques
  • When not to use mod_rewrite

From Old to New (internal)

Description:

Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for backward compatibility. However, we want that users of the old URL even not recognize that the pages was renamed - that is, we don't want the address to change in their browser.

Solution:

We rewrite the old URL to the new one internally via the following rule:

RewriteEngine on RewriteRule "^/foo\.html$" "/bar.html" [PT]

Rewriting From Old to New (external)

Description:
Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL for backward compatibility. But this time we want that the users of the old URL get hinted to the new one, i.e. their browsers Location field should change, too.
Solution:
We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:

RewriteEngine on RewriteRule "^/foo\.html$" "bar.html" [R]

Discussion
In this example, as contrasted to the internal example above, we can simply use the Redirect directive. mod_rewrite was used in that earlier example in order to hide the redirect from the client:

Redirect "/foo.html" "/bar.html"

Resource Moved to Another Server

Description:

If a resource has moved to another server, you may wish to have URLs continue to work for a time on the old server while people update their bookmarks.

Solution:

You can use mod_rewrite to redirect these URLs to the new server, but you might also consider using the Redirect or RedirectMatch directive.

#With mod_rewrite RewriteEngine on RewriteRule "^/docs/(.+)" "http://new.example.com/docs/$1" [R,L] #With RedirectMatch RedirectMatch "^/docs/(.*)" "http://new.example.com/docs/$1" #With Redirect Redirect "/docs/" "http://new.example.com/docs/"

From Static to Dynamic

Description:
How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without notice by the browser/user.
Solution:
We just rewrite the URL to the CGI-script and force the handler to be cgi-script so that it is executed as a CGI program. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.cgi.

RewriteEngine on RewriteBase "/~quux/" RewriteRule "^foo\.html$" "foo.cgi" [H=cgi-script]

Backward Compatibility for file extension change

Description:
How can we make URLs backward compatible (still existing virtually) after migrating document.YYYY to document.XXXX, e.g. after translating a bunch of .html files to .php?
Solution:
We rewrite the name to its basename and test for existence of the new extension. If it exists, we take that name, else we rewrite the URL to its original state.

# backward compatibility ruleset for # rewriting document.html to document.php # when and only when document.php exists <Directory "/var/www/htdocs">

RewriteEngine on
RewriteBase "/var/www/htdocs"
RewriteCond "$1.php" -f
RewriteCond "$1.html" !-f
RewriteRule "^(.*).html$" "$1.php"

</Directory>

Discussion
This example uses an often-overlooked feature of mod_rewrite, by taking advantage of the order of execution of the ruleset. In particular, mod_rewrite evaluates the left-hand-side of the RewriteRule before it evaluates the RewriteCond directives. 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.
This ruleset is designed to use in a per-directory context (In a <Directory> block or in a .htaccess file), so that the -f checks are looking at the correct directory path. You may need to set a RewriteBase directive to specify the directory base that you're working in.

Canonical Hostnames

Description:
The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of example.com, you might use a variant of the following recipe.
Solution:
The very best way to solve this doesn't involve mod_rewrite at all, but rather uses the Redirect directive placed in a virtual host for the non-canonical hostname(s).

<VirtualHost *:80>

ServerName undesired.example.com
ServerAlias example.com notthis.example.com
Redirect "/" "http://www.example.com/"

</VirtualHost>

<VirtualHost *:80>

ServerName www.example.com

</VirtualHost>

You can alternatively accomplish this using the <If> directive:

<If "%{HTTP_HOST} != 'www.example.com'">

Redirect "/" "http://www.example.com/"

</If>

Or, for example, to redirect a portion of your site to HTTPS, you might do the following:

<If "%{SERVER_PROTOCOL} != 'HTTPS'">

Redirect "/admin/" "https://www.example.com/admin/"

</If>

If, for whatever reason, you still want to use mod_rewrite - if, for example, you need this to work with a larger set of RewriteRules - you might use one of the recipes below.
For sites running on a port other than 80:

RewriteCond "%{HTTP_HOST}" "!^www\.example\.com" [NC] RewriteCond "%{HTTP_HOST}" "!^$" RewriteCond "%{SERVER_PORT}" "!^80$" RewriteRule "^/?(.*)" "http://www.example.com:%{SERVER_PORT}/$1" [L,R,NE]

And for a site running on port 80

RewriteCond "%{HTTP_HOST}" "!^www\.example\.com" [NC] RewriteCond "%{HTTP_HOST}" "!^$" RewriteRule "^/?(.*)" "http://www.example.com/$1" [L,R,NE]

If you wanted to do this generically for all domain names - that is, if you want to redirect example.com to www.example.com for all possible values of example.com, you could use the following recipe:

RewriteCond "%{HTTP_HOST}" "!^www\." [NC] RewriteCond "%{HTTP_HOST}" "!^$" RewriteRule "^/?(.*)" "http://www.%{HTTP_HOST}/$1" [L,R,NE]

These rulesets will work either in your main server configuration file, or in a .htaccess file placed in the DocumentRoot of the server.

Search for pages in more than one directory

Description:
A particular resource might exist in one of several places, and we want to look in those places for the resource when it is requested. Perhaps we've recently rearranged our directory structure, dividing content into several locations.
Solution:
The following ruleset searches in two directories to find the resource, and, if not finding it in either place, will attempt to just serve it out of the location requested.

RewriteEngine on

# first try to find it in dir1/... # ...and if found stop and be happy: RewriteCond "%{DOCUMENT_ROOT}/dir1/%{REQUEST_URI}" -f RewriteRule "^(.+)" "%{DOCUMENT_ROOT}/dir1/$1" [L]

# second try to find it in dir2/... # ...and if found stop and be happy: RewriteCond "%{DOCUMENT_ROOT}/dir2/%{REQUEST_URI}" -f RewriteRule "^(.+)" "%{DOCUMENT_ROOT}/dir2/$1" [L]

# else go on for other Alias or ScriptAlias directives, # etc. RewriteRule "^" "-" [PT]

Redirecting to Geographically Distributed Servers

Description:
We have numerous mirrors of our website, and want to redirect people to the one that is located in the country where they are located.
Solution:
Looking at the hostname of the requesting client, we determine which country they are coming from. If we can't do a lookup on their IP address, we fall back to a default server.
We'll use a RewriteMap directive to build a list of servers that we wish to use.

HostnameLookups on RewriteEngine on RewriteMap multiplex "txt:/path/to/map.mirrors" RewriteCond "%{REMOTE_HOST}" "([a-z]+)$" [NC] RewriteRule "^/(.*)$" "${multiplex:%1|http://www.example.com/}$1" [R,L] ## map.mirrors -- Multiplexing Map

de http://www.example.de/
uk http://www.example.uk/
com http://www.example.com/
##EOF## 
Discussion
This ruleset relies on HostNameLookups being set on, which can be a significant performance hit.
The RewriteCond directive captures the last portion of the hostname of the requesting client - the country code - and the following RewriteRule uses that value to look up the appropriate mirror host in the map file.

Browser Dependent Content

Description:
We wish to provide different content based on the browser, or user-agent, which is requesting the content.
Solution:
We have to decide, based on the HTTP header "User-Agent", which content to serve. The following config does the following: If the HTTP header "User-Agent" contains "Mozilla/3", the page foo.html is rewritten to foo.NS.html and the rewriting stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2, the URL becomes foo.20.html. All other browsers receive page foo.32.html. This is done with the following ruleset:

RewriteCond "%{HTTP_USER_AGENT}" "^Mozilla/3.*" RewriteRule "^foo\.html$" "foo.NS.html" [L]

RewriteCond "%{HTTP_USER_AGENT}" "^Lynx/" [OR] RewriteCond "%{HTTP_USER_AGENT}" "^Mozilla/[12]" RewriteRule "^foo\.html$" "foo.20.html" [L]

RewriteRule "^foo\.html$" "foo.32.html" [L]

Canonical URLs

Description:

On some webservers there is more than one URL for a resource. Usually there are canonical URLs (which are be actually used and distributed) and those which are just shortcuts, internal ones, and so on. Independent of which URL the user supplied with the request, they should finally see the canonical one in their browser address bar.

Solution:
We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser and for all subsequent requests. In the example ruleset below we replace /puppies and /canines by the canonical /dogs.

RewriteRule "^/(puppies|canines)/(.*)" "/dogs/$2" [R]

Discussion:
This should really be accomplished with Redirect or RedirectMatch directives:

RedirectMatch "^/(puppies|canines)/(.*)" "/dogs/$2"

Moved DocumentRoot

Description:
Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not really of top-level priority. For example, you may wish for visitors, on first entering a site, to go to a particular subdirectory /about/. This may be accomplished using the following ruleset:
Solution:
We redirect the URL / to /about/:

RewriteEngine on RewriteRule "^/$" "/about/" [R]

Note that this can also be handled using the RedirectMatch directive:

RedirectMatch "^/$" "http://example.com/about/"

Note also that the example rewrites only the root URL. That is, it rewrites a request for http://example.com/, but not a request for http://example.com/page.html. If you have in fact changed your document root - that is, if all of your content is in fact in that subdirectory, it is greatly preferable to simply change your DocumentRoot directive, or move all of the content up one directory, rather than rewriting URLs.

Fallback Resource

Description:

You want a single resource (say, a certain file, like index.php) to handle all requests that come to a particular directory, except those that should go to an existing resource such as an image, or a css file.

Solution:
As of version 2.2.16, you should use the FallbackResource directive for this:

<Directory "/var/www/my_blog">

FallbackResource "index.php"

</Directory>

However, in earlier versions of Apache, or if your needs are more complicated than this, you can use a variation of the following rewrite set to accomplish the same thing:

<Directory "/var/www/my_blog">

RewriteBase "/my_blog"
RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-f
RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-d
RewriteRule "^" "index.php" [PT]

</Directory>

If, on the other hand, you wish to pass the requested URI as a query string argument to index.php, you can replace that RewriteRule with:

RewriteRule "(.*)" "index.php?$1" [PT,QSA]

Note that these rulesets can be used in a .htaccess file, as well as in a <Directory> block.

Rewrite query string

Description:
You want to capture a particular value from a query string and either replace it or incorporate it into another component of the URL.
Solutions:
Many of the solutions in this section will all use the same condition, which leaves the matched value in the %2 backreference. %1 is the beginining of the query string (up to the key of intererest), and %3 is the remainder. This condition is a bit complex for flexibility and to avoid double '&&' in the substitutions.

* This solution removes the matching key and value:
# Remove mykey=???
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
RewriteRule "(.*)" "$1?%1%3"

  • This solution uses the captured value in the URL subsitution, discarding the rest of the original query by appending a '?':
    # Copy from query string to PATH_INFO
    RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
    RewriteRule "(.*)" "$1/products/%2/?" [PT]
  • This solution checks the captured value in a subsequent condition:
    # Capture the value of mykey in the query string
    RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
    RewriteCond "%2" !=not-so-secret-value
    RewriteRule "(.*)" - [F]
  • This solution shows the reverse of the previous ones, copying path components (perhaps PATH_INFO) from the URL into the query string.
    # The desired URL might be /products/kitchen-sink, and the script expects
    # /path?products=kitchen-sink.
    RewriteRule "^/?path/([^/]+)/([^/]+)" "/path?$1=$2" [PT]

Apache mod_rewrite Introduction

This document supplements the mod_rewrite reference documentation. It describes the basic concepts necessary for use of mod_rewrite. Other documents go into greater detail, but this doc should help the beginner get their feet wet. * Introduction

  • Regular Expressions
  • RewriteRule Basics
  • Rewrite Flags
  • Rewrite Conditions
  • Rewrite maps
  • .htaccess files

See also

  • Module documentation
  • Redirection and remapping
  • Controlling access
  • Virtual hosts
  • Proxying
  • Using RewriteMap
  • Advanced techniques
  • When not to use mod_rewrite
  • Comments

Introduction

The Apache module mod_rewrite is a very powerful and sophisticated module which provides a way to do URL manipulations. With it, you can do nearly all types of URL rewriting that you may need. It is, however, somewhat complex, and may be intimidating to the beginner. There is also a tendency to treat rewrite rules as magic incantation, using them without actually understanding what they do.

This document attempts to give sufficient background so that what follows is understood, rather than just copied blindly.

Remember that many common URL-manipulation tasks don't require the full power and complexity of mod_rewrite. For simple tasks, see mod_alias and the documentation on mapping URLs to the filesystem.

Finally, before proceeding, be sure to configure mod_rewrite's log level to one of the trace levels using the LogLevel directive. Although this can give an overwhelming amount of information, it is indispensable in debugging problems with mod_rewrite configuration, since it will tell you exactly how each rule is processed.

Regular Expressions

mod_rewrite uses the Perl Compatible Regular Expression vocabulary. In this document, we do not attempt to provide a detailed reference to regular expressions. For that, we recommend the PCRE man pages, the Perl regular expression man page, and Mastering Regular Expressions, by Jeffrey Friedl.

In this document, we attempt to provide enough of a regex vocabulary to get you started, without being overwhelming, in the hope that RewriteRules will be scientific formulae, rather than magical incantations.

Regex vocabulary

The following are the minimal building blocks you will need, in order to write regular expressions and RewriteRules. They certainly do not represent a complete regular expression vocabulary, but they are a good place to start, and should help you read basic regular expressions, as well as write your own.

Character Meaning Example
. Matches any single character c.t will match cat, cot, cut, etc.
+ Repeats the previous match one or more times a+ matches a, aa, aaa, etc
* Repeats the previous match zero or more times. a* matches all the same things a+ matches, but will also match an empty string.
? Makes the match optional. colou?r will match color and colour.
^ Called an anchor, matches the beginning of the string ^a matches a string that begins with a
$ The other anchor, this matches the end of the string. a$ matches a string that ends with a.
( ) Groups several characters into a single unit, and captures a match for use in a backreference. (ab)+ matches ababab - that is, the + applies to the group. For more on backreferences see below.
[ ] A character class - matches one of the characters c[uoa]t matches cut, cot or cat.
[^ ] Negative character class - matches any character not specified c[^/]t matches cat or c=t but not c/t

In mod_rewrite the ! character can be used before a regular expression to negate it. This is, a string will be considered to have matched only if it does not match the rest of the expression.

Regex Back-Reference Availability

One important thing here has to be remembered: Whenever you use parentheses in Pattern or in one of the CondPattern, back-references are internally created which can be used with the strings $N and %N (see below). These are available for creating the Substitution parameter of a RewriteRule or the TestString parameter of a RewriteCond.

Captures in the RewriteRule patterns are (counterintuitively) available to all preceding RewriteCond directives, because the RewriteRule expression is evaluated before the individual conditions.

Figure 1 shows to which locations the back-references are transferred for expansion as well as illustrating the flow of the RewriteRule, RewriteCond matching. In the next chapters, we will be exploring how to use these back-references, so do not fret if it seems a bit alien to you at first.

"Flow of RewriteRule and RewriteCond matching"

Figure 1: The back-reference flow through a rule.

In this example, a request for /test/1234 would be transformed into /admin.foo?page=test&id=1234&host=admin.example.com.

RewriteRule Basics

A RewriteRule consists of three arguments separated by spaces. The arguments are# Pattern: which incoming URLs should be affected by the rule;

  1. Substitution: where should the matching requests be sent;
  2. [flags]: options affecting the rewritten request.

The Pattern is a regular expression. It is initially (for the first rewrite rule or until a substitution occurs) matched against the URL-path of the incoming request (the part after the hostname but before any question mark indicating the beginning of a query string) or, in per-directory context, against the request's path relative to the directory for which the rule is defined. Once a substitution has occurred, the rules that follow are matched against the substituted value.

"Syntax of the RewriteRule directive"

Figure 2: Syntax of the RewriteRule directive.

The Substitution can itself be one of three things:

A full filesystem path to a resource

RewriteRule "^/games" "/usr/local/games/web"

This maps a request to an arbitrary location on your filesystem, much like the Alias directive.
A web-path to a resource

RewriteRule "^/foo$" "/bar"

If DocumentRoot is set to /usr/local/apache2/htdocs, then this directive would map requests for http://example.com/foo to the path /usr/local/apache2/htdocs/bar.
An absolute URL

RewriteRule "^/product/view$" "http://site2.example.com/seeproduct.html" [R]

This tells the client to make a new request for the specified URL.

The Substitution can also contain back-references to parts of the incoming URL-path matched by the Pattern. Consider the following:

RewriteRule "^/product/(.*)/view$" "/var/web/productdb/$1"

The variable $1 will be replaced with whatever text was matched by the expression inside the parenthesis in the Pattern. For example, a request for http://example.com/product/r14df/view will be mapped to the path /var/web/productdb/r14df.

If there is more than one expression in parenthesis, they are available in order in the variables $1, $2, $3, and so on.

Rewrite Flags

The behavior of a RewriteRule can be modified by the application of one or more flags to the end of the rule. For example, the matching behavior of a rule can be made case-insensitive by the application of the [NC] flag:

RewriteRule "^puppy.html" "smalldog.html" [NC]

For more details on the available flags, their meanings, and examples, see the Rewrite Flags document.

Rewrite Conditions

One or more RewriteCond directives can be used to restrict the types of requests that will be subject to the following RewriteRule. The first argument is a variable describing a characteristic of the request, the second argument is a regular expression that must match the variable, and a third optional argument is a list of flags that modify how the match is evaluated.

"Syntax of the RewriteCond directive"

Figure 3: Syntax of the RewriteCond directive

For example, to send all requests from a particular IP range to a different server, you could use:

RewriteCond "%{REMOTE_ADDR}" "^10\.2\." RewriteRule "(.*)" "http://intranet.example.com$1"

When more than one RewriteCond is specified, they must all match for the RewriteRule to be applied. For example, to deny requests that contain the word "hack" in their query string, unless they also contain a cookie containing the word "go", you could use:

RewriteCond "%{QUERY_STRING}" "hack" RewriteCond "%{HTTP_COOKIE}" "!go" RewriteRule "." "-" [F]

Notice that the exclamation mark specifies a negative match, so the rule is only applied if the cookie does not contain "go".

Matches in the regular expressions contained in the RewriteConds can be used as part of the Substitution in the RewriteRule using the variables %1, %2, etc. For example, this will direct the request to a different directory depending on the hostname used to access the site:

RewriteCond "%{HTTP_HOST}" "(.*)" RewriteRule "^/(.*)" "/sites/%1/$1"

If the request was for http://example.com/foo/bar, then %1 would contain example.com and $1 would contain foo/bar.

Rewrite maps

The RewriteMap directive provides a way to call an external function, so to speak, to do your rewriting for you. This is discussed in greater detail in the RewriteMap supplementary documentation.

.htaccess files

Rewriting is typically configured in the main server configuration setting (outside any <Directory> section) or inside <VirtualHost> containers. This is the easiest way to do rewriting and is recommended. It is possible, however, to do rewriting inside <Directory> sections or .htaccess files at the expense of some additional complexity. This technique is called per-directory rewrites.

The main difference with per-server rewrites is that the path prefix of the directory containing the .htaccess file is stripped before matching in the RewriteRule. In addition, the RewriteBase should be used to assure the request is properly mapped.

RewriteRule Flags

This document discusses the flags which are available to the RewriteRule directive, providing detailed explanations and examples.* Introduction

  • B (escape backreferences)
  • BNP|backrefnoplus (don't escape space to +)
  • C|chain
  • CO|cookie
  • DPI|discardpath
  • E|env
  • END
  • F|forbidden
  • G|gone
  • H|handler
  • L|last
  • N|next
  • NC|nocase
  • NE|noescape
  • NS|nosubreq
  • P|proxy
  • PT|passthrough
  • QSA|qsappend
  • QSD|qsdiscard
  • QSL|qslast
  • R|redirect
  • S|skip
  • T|type

See also

  • Module documentation
  • mod_rewrite introduction
  • Redirection and remapping
  • Controlling access
  • Virtual hosts
  • Proxying
  • Using RewriteMap
  • Advanced techniques
  • When not to use mod_rewrite

Introduction

A RewriteRule can have its behavior modified by one or more flags. Flags are included in square brackets at the end of the rule, and multiple flags are separated by commas.

RewriteRule pattern target [Flag1,Flag2,Flag3]

Each flag (with a few exceptions) has a short form, such as CO, as well as a longer form, such as cookie. While it is most common to use the short form, it is recommended that you familiarize yourself with the long form, so that you remember what each flag is supposed to do. Some flags take one or more arguments. Flags are not case sensitive.

Flags that alter metadata associated with the request (T=, H=, E=) have no affect in per-directory and htaccess context, when a substitution (other than '-') is performed during the same round of rewrite processing.

Presented here are each of the available flags, along with an example of how you might use them.

B (escape backreferences)

The [B] flag instructs RewriteRule to escape non-alphanumeric characters before applying the transformation.

In 2.4.26 and later, you can limit the escaping to specific characters in backreferences by listing them: [B=#?;]. Note: The space character can be used in the list of characters to escape, but it cannot be the last character in the list.

mod_rewrite has to unescape URLs before mapping them, so backreferences are unescaped at the time they are applied. Using the B flag, non-alphanumeric characters in backreferences will be escaped. For example, consider the rule:

RewriteRule "^search/(.*)$" "/search.php?term=$1"

Given a search term of 'x & y/z', a browser will encode it as 'x%20%26%20y%2Fz', making the request 'search/x%20%26%20y%2Fz'. Without the B flag, this rewrite rule will map to 'search.php?term=x & y/z', which isn't a valid URL, and so would be encoded as search.php?term=x%20&y%2Fz=, which is not what was intended.

With the B flag set on this same rule, the parameters are re-encoded before being passed on to the output URL, resulting in a correct mapping to /search.php?term=x%20%26%20y%2Fz.

RewriteRule "^search/(.*)$" "/search.php?term=$1" [B,PT]

Note that you may also need to set AllowEncodedSlashes to On to get this particular example to work, as httpd does not allow encoded slashes in URLs, and returns a 404 if it sees one.

This escaping is particularly necessary in a proxy situation, when the backend may break if presented with an unescaped URL.

An alternative to this flag is using a RewriteCond to capture against %{THE_REQUEST} which will capture strings in the encoded form.

BNP|backrefnoplus (don't escape space to +)

The [BNP] flag instructs RewriteRule to escape the space character in a backreference to %20 rather than '+'. Useful when the backreference will be used in the path component rather than the query string.

This flag is available in version 2.4.26 and later.

C|chain

The [C] or [chain] flag indicates that the RewriteRule is chained to the next rule. That is, if the rule matches, then it is processed as usual and control moves on to the next rule. However, if it does not match, then the next rule, and any other rules that are chained together, are skipped.

CO|cookie

The [CO], or [cookie] flag, allows you to set a cookie when a particular RewriteRule matches. The argument consists of three required fields and four optional fields.

The full syntax for the flag, including all attributes, is as follows:

[CO=NAME:VALUE:DOMAIN:lifetime:path:secure:httponly]

If a literal ':' character is needed in any of the cookie fields, an alternate syntax is available. To opt-in to the alternate syntax, the cookie "Name" should be preceded with a ';' character, and field separators should be specified as ';'.

[CO=;NAME;VALUE:MOREVALUE;DOMAIN;lifetime;path;secure;httponly]

You must declare a name, a value, and a domain for the cookie to be set.

Domain
The domain for which you want the cookie to be valid. This may be a hostname, such as www.example.com, or it may be a domain, such as .example.com. It must be at least two parts separated by a dot. That is, it may not be merely .com or .net. Cookies of that kind are forbidden by the cookie security model.

You may optionally also set the following values:

Lifetime
The time for which the cookie will persist, in minutes.
A value of 0 indicates that the cookie will persist only for the current browser session. This is the default value if none is specified.
Path
The path, on the current website, for which the cookie is valid, such as /customers/ or /files/download/.
By default, this is set to / - that is, the entire website.
Secure
If set to secure, true, or 1, the cookie will only be permitted to be translated via secure (https) connections.
httponly
If set to HttpOnly, true, or 1, the cookie will have the HttpOnly flag set, which means that the cookie is inaccessible to JavaScript code on browsers that support this feature.

Consider this example:

RewriteEngine On RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/]

In the example give, the rule doesn't rewrite the request. The "-" rewrite target tells mod_rewrite to pass the request through unchanged. Instead, it sets a cookie called 'frontdoor' to a value of 'yes'. The cookie is valid for any host in the .example.com domain. It is set to expire in 1440 minutes (24 hours) and is returned for all URIs.

DPI|discardpath

The DPI flag causes the PATH_INFO portion of the rewritten URI to be discarded.

This flag is available in version 2.2.12 and later.

In per-directory context, the URI each RewriteRule compares against is the concatenation of the current values of the URI and PATH_INFO.

The current URI can be the initial URI as requested by the client, the result of a previous round of mod_rewrite processing, or the result of a prior rule in the current round of mod_rewrite processing.

In contrast, the PATH_INFO that is appended to the URI before each rule reflects only the value of PATH_INFO before this round of mod_rewrite processing. As a consequence, if large portions of the URI are matched and copied into a substitution in multiple RewriteRule directives, without regard for which parts of the URI came from the current PATH_INFO, the final URI may have multiple copies of PATH_INFO appended to it.

Use this flag on any substitution where the PATH_INFO that resulted from the previous mapping of this request to the filesystem is not of interest. This flag permanently forgets the PATH_INFO established before this round of mod_rewrite processing began. PATH_INFO will not be recalculated until the current round of mod_rewrite processing completes. Subsequent rules during this round of processing will see only the direct result of substitutions, without any PATH_INFO appended.

E|env

With the [E], or [env] flag, you can set the value of an environment variable. Note that some environment variables may be set after the rule is run, thus unsetting what you have set. See the Environment Variables document for more details on how Environment variables work.

The full syntax for this flag is:

[E=VAR:VAL] [E=!VAR]

VAL may contain backreferences ($N or %N) which are expanded.

Using the short form

[E=VAR]

you can set the environment variable named VAR to an empty value.

The form

[E=!VAR]

allows to unset a previously set environment variable named VAR.

Environment variables can then be used in a variety of contexts, including CGI programs, other RewriteRule directives, or CustomLog directives.

The following example sets an environment variable called 'image' to a value of '1' if the requested URI is an image file. Then, that environment variable is used to exclude those requests from the access log.

RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1] CustomLog "logs/access_log" combined env=!image

Note that this same effect can be obtained using SetEnvIf. This technique is offered as an example, not as a recommendation.

END

Using the [END] flag terminates not only the current round of rewrite processing (like [L]) but also prevents any subsequent rewrite processing from occurring in per-directory (htaccess) context.

This does not apply to new requests resulting from external redirects.

F|forbidden

Using the [F] flag causes the server to return a 403 Forbidden status code to the client. While the same behavior can be accomplished using the Deny directive, this allows more flexibility in assigning a Forbidden status.

The following rule will forbid .exe files from being downloaded from your server.

RewriteRule "\.exe" "-" [F]

This example uses the "-" syntax for the rewrite target, which means that the requested URI is not modified. There's no reason to rewrite to another URI, if you're going to forbid the request.

When using [F], an [L] is implied - that is, the response is returned immediately, and no further rules are evaluated.

G|gone

The [G] flag forces the server to return a 410 Gone status with the response. This indicates that a resource used to be available, but is no longer available.

As with the [F] flag, you will typically use the "-" syntax for the rewrite target when using the [G] flag:

RewriteRule "oldproduct" "-" [G,NC]

When using [G], an [L] is implied - that is, the response is returned immediately, and no further rules are evaluated.

H|handler

Forces the resulting request to be handled with the specified handler. For example, one might use this to force all files without a file extension to be parsed by the php handler:

RewriteRule "!\." "-" [H=application/x-httpd-php]

The regular expression above - !\. - will match any request that does not contain the literal . character.

This can be also used to force the handler based on some conditions. For example, the following snippet used in per-server context allows .php files to be displayed by mod_php if they are requested with the .phps extension:

RewriteRule "^(/source/.+\.php)s$" "$1" [H=application/x-httpd-php-source]

The regular expression above - ^(/source/.+\.php)s$ - will match any request that starts with /source/ followed by 1 or n characters followed by .phps literally. The backreference $1 referrers to the captured match within parenthesis of the regular expression.

L|last

The [L] flag causes mod_rewrite to stop processing the rule set. In most contexts, this means that if the rule matches, no further rules will be processed. This corresponds to the last command in Perl, or the break command in C. Use this flag to indicate that the current rule should be applied immediately without considering further rules.

If you are using RewriteRule in either .htaccess files or in <Directory> sections, it is important to have some understanding of how the rules are processed. The simplified form of this is that once the rules have been processed, the rewritten request is handed back to the URL parsing engine to do what it may with it. It is possible that as the rewritten request is handled, the .htaccess file or <Directory> section may be encountered again, and thus the ruleset may be run again from the start. Most commonly this will happen if one of the rules causes a redirect - either internal or external - causing the request process to start over.

It is therefore important, if you are using RewriteRule directives in one of these contexts, that you take explicit steps to avoid rules looping, and not count solely on the [L] flag to terminate execution of a series of rules, as shown below.

An alternative flag, [END], can be used to terminate not only the current round of rewrite processing but prevent any subsequent rewrite processing from occurring in per-directory (htaccess) context. This does not apply to new requests resulting from external redirects.

The example given here will rewrite any request to index.php, giving the original request as a query string argument to index.php, however, the RewriteCond ensures that if the request is already for index.php, the RewriteRule will be skipped.

RewriteBase "/" RewriteCond "%{REQUEST_URI}" "!=/index.php" RewriteRule "^(.*)" "/index.php?req=$1" [L,PT]

N|next

The [N] flag causes the ruleset to start over again from the top, using the result of the ruleset so far as a starting point. Use with extreme caution, as it may result in loop.

The [Next] flag could be used, for example, if you wished to replace a certain string or letter repeatedly in a request. The example shown here will replace A with B everywhere in a request, and will continue doing so until there are no more As to be replaced.

RewriteRule "(.*)A(.*)" "$1B$2" [N]

You can think of this as a while loop: While this pattern still matches (i.e., while the URI still contains an A), perform this substitution (i.e., replace the A with a B).

In 2.4.8 and later, this module returns an error after 32,000 iterations to protect against unintended looping. An alternative maximum number of iterations can be specified by adding to the N flag.

# Be willing to replace 1 character in each pass of the loop RewriteRule "(.+)[><;]$" "$1" [N=64000] # ... or, give up if after 10 loops RewriteRule "(.+)[><;]$" "$1" [N=10]

NC|nocase

Use of the [NC] flag causes the RewriteRule to be matched in a case-insensitive manner. That is, it doesn't care whether letters appear as upper-case or lower-case in the matched URI.

In the example below, any request for an image file will be proxied to your dedicated image server. The match is case-insensitive, so that .jpg and .JPG files are both acceptable, for example.

RewriteRule "(.*\.(jpg|gif|png))$" "http://images.example.com$1" [P,NC]

NE|noescape

By default, special characters, such as & and ?, for example, will be converted to their hexcode equivalent. Using the [NE] flag prevents that from happening.

RewriteRule "^/anchor/(.+)" "/bigpage.html#$1" [NE,R]

The above example will redirect /anchor/xyz to /bigpage.html#xyz. Omitting the [NE] will result in the # being converted to its hexcode equivalent, %23, which will then result in a 404 Not Found error condition.

NS|nosubreq

Use of the [NS] flag prevents the rule from being used on subrequests. For example, a page which is included using an SSI (Server Side Include) is a subrequest, and you may want to avoid rewrites happening on those subrequests. Also, when mod_dir tries to find out information about possible directory default files (such as index.html files), this is an internal subrequest, and you often want to avoid rewrites on such subrequests. On subrequests, it is not always useful, and can even cause errors, if the complete set of rules are applied. Use this flag to exclude problematic rules.

To decide whether or not to use this rule: if you prefix URLs with CGI-scripts, to force them to be processed by the CGI-script, it's likely that you will run into problems (or significant overhead) on sub-requests. In these cases, use this flag.

Images, javascript files, or css files, loaded as part of an HTML page, are not subrequests - the browser requests them as separate HTTP requests.

P|proxy

Use of the [P] flag causes the request to be handled by mod_proxy, and handled via a proxy request. For example, if you wanted all image requests to be handled by a back-end image server, you might do something like the following:

RewriteRule "/(.*)\.(jpg|gif|png)$" "http://images.example.com/$1.$2" [P]

Use of the [P] flag implies [L] - that is, the request is immediately pushed through the proxy, and any following rules will not be considered.

You must make sure that the substitution string is a valid URI (typically starting with http://hostname) which can be handled by the mod_proxy. If not, you will get an error from the proxy module. Use this flag to achieve a more powerful implementation of the ProxyPass directive, to map remote content into the namespace of the local server.

Security Warning

Take care when constructing the target URL of the rule, considering the security impact from allowing the client influence over the set of URLs to which your server will act as a proxy. Ensure that the scheme and hostname part of the URL is either fixed, or does not allow the client undue influence.

Performance warning

Using this flag triggers the use of mod_proxy, without handling of persistent connections. This means the performance of your proxy will be better if you set it up with ProxyPass or ProxyPassMatch

This is because this flag triggers the use of the default worker, which does not handle connection pooling/reuse.

Avoid using this flag and prefer those directives, whenever you can.

Note: mod_proxy must be enabled in order to use this flag.

PT|passthrough

The target (or substitution string) in a RewriteRule is assumed to be a file path, by default. The use of the [PT] flag causes it to be treated as a URI instead. That is to say, the use of the [PT] flag causes the result of the RewriteRule to be passed back through URL mapping, so that location-based mappings, such as Alias, Redirect, or ScriptAlias, for example, might have a chance to take effect.

If, for example, you have an Alias for /icons, and have a RewriteRule pointing there, you should use the [PT] flag to ensure that the Alias is evaluated.

Alias "/icons" "/usr/local/apache/icons" RewriteRule "/pics/(.+)\.jpg$" "/icons/$1.gif" [PT]

Omission of the [PT] flag in this case will cause the Alias to be ignored, resulting in a 'File not found' error being returned.

The PT flag implies the L flag: rewriting will be stopped in order to pass the request to the next phase of processing.

Note that the PT flag is implied in per-directory contexts such as <Directory> sections or in .htaccess files. The only way to circumvent that is to rewrite to -.

QSA|qsappend

When the replacement URI contains a query string, the default behavior of RewriteRule is to discard the existing query string, and replace it with the newly generated one. Using the [QSA] flag causes the query strings to be combined.

Consider the following rule:

RewriteRule "/pages/(.+)" "/page.php?page=$1" [QSA]

With the [QSA] flag, a request for /pages/123?one=two will be mapped to /page.php?page=123&one=two. Without the [QSA] flag, that same request will be mapped to /page.php?page=123 - that is, the existing query string will be discarded.

QSD|qsdiscard

When the requested URI contains a query string, and the target URI does not, the default behavior of RewriteRule is to copy that query string to the target URI. Using the [QSD] flag causes the query string to be discarded.

This flag is available in version 2.4.0 and later.

Using [QSD] and [QSA] together will result in [QSD] taking precedence.

If the target URI has a query string, the default behavior will be observed - that is, the original query string will be discarded and replaced with the query string in the RewriteRule target URI.

QSL|qslast

By default, the first (left-most) question mark in the substitution delimits the path from the query string. Using the [QSL] flag instructs RewriteRule to instead split the two components using the last (right-most) question mark.

This is useful when mapping to files that have literal question marks in their filename. If no query string is used in the substitution, a question mark can be appended to it in combination with this flag.

This flag is available in version 2.4.19 and later.

R|redirect

Use of the [R] flag causes a HTTP redirect to be issued to the browser. If a fully-qualified URL is specified (that is, including http://servername/) then a redirect will be issued to that location. Otherwise, the current protocol, servername, and port number will be used to generate the URL sent with the redirect.

Any valid HTTP response status code may be specified, using the syntax [R=305], with a 302 status code being used by default if none is specified. The status code specified need not necessarily be a redirect (3xx) status code. However, if a status code is outside the redirect range (300-399) then the substitution string is dropped entirely, and rewriting is stopped as if the L were used.

In addition to response status codes, you may also specify redirect status using their symbolic names: temp (default), permanent, or seeother.

You will almost always want to use [R] in conjunction with [L] (that is, use [R,L]) because on its own, the [R] flag prepends http://thishost[:thisport] to the URI, but then passes this on to the next rule in the ruleset, which can often result in 'Invalid URI in request' warnings.

S|skip

The [S] flag is used to skip rules that you don't want to run. The syntax of the skip flag is [S=N], where N signifies the number of rules to skip (provided the RewriteRule matches). This can be thought of as a goto statement in your rewrite ruleset. In the following example, we only want to run the RewriteRule if the requested URI doesn't correspond with an actual file.

# Is the request for a non-existent file? RewriteCond "%{REQUEST_FILENAME}" "!-f" RewriteCond "%{REQUEST_FILENAME}" "!-d" # If so, skip these two RewriteRules RewriteRule ".?" "-" [S=2]

RewriteRule "(.*\.gif)" "images.php?$1" RewriteRule "(.*\.html)" "docs.php?$1"

This technique is useful because a RewriteCond only applies to the RewriteRule immediately following it. Thus, if you want to make a RewriteCond apply to several RewriteRules, one possible technique is to negate those conditions and add a RewriteRule with a [Skip] flag. You can use this to make pseudo if-then-else constructs: The last rule of the then-clause becomes skip=N, where N is the number of rules in the else-clause:

# Does the file exist? RewriteCond "%{REQUEST_FILENAME}" "!-f" RewriteCond "%{REQUEST_FILENAME}" "!-d" # Create an if-then-else construct by skipping 3 lines if we meant to go to the "else" stanza. RewriteRule ".?" "-" [S=3]

# IF the file exists, then:

RewriteRule "(.*\.gif)" "images.php?$1"
RewriteRule "(.*\.html)" "docs.php?$1"
# Skip past the "else" stanza.
RewriteRule ".?" "-" [S=1]

# ELSE...

RewriteRule "(.*)" "404.php?file=$1"

# END

It is probably easier to accomplish this kind of configuration using the <If>, <ElseIf>, and <Else> directives instead.

T|type

Sets the MIME type with which the resulting response will be sent. This has the same effect as the AddType directive.

For example, you might use the following technique to serve Perl source code as plain text, if requested in a particular way:

# Serve .pl files as plain text RewriteRule "\.pl$" "-" [T=text/plain]

Or, perhaps, if you have a camera that produces jpeg images without file extensions, you could force those images to be served with the correct MIME type by virtue of their file names:

# Files with 'IMG' in the name are jpg images. RewriteRule "IMG" "-" [T=image/jpg]

Please note that this is a trivial example, and could be better done using <FilesMatch> instead. Always consider the alternate solutions to a problem before resorting to rewrite, which will invariably be a less efficient solution than the alternatives.

If used in per-directory context, use only - (dash) as the substitution for the entire round of mod_rewrite processing, otherwise the MIME-type set with this flag is lost due to an internal re-processing (including subsequent rounds of mod_rewrite processing). The L flag can be useful in this context to end the current round of mod_rewrite processing.

Advanced Techniques with mod_rewrite

This document supplements the mod_rewrite reference documentation. It provides a few advanced techniques using mod_rewrite.

Note that many of these examples won't work unchanged in your particular server configuration, so it's important that you understand them, rather than merely cutting and pasting the examples into your configuration.* URL-based sharding across multiple backends

  • On-the-fly Content-Regeneration
  • Load Balancing
  • Structured Userdirs
  • Redirecting Anchors
  • Time-Dependent Rewriting
  • Set Environment Variables Based On URL Parts

See also

  • Module documentation
  • mod_rewrite introduction
  • Redirection and remapping
  • Controlling access
  • Virtual hosts
  • Proxying
  • Using RewriteMap
  • When not to use mod_rewrite

URL-based sharding across multiple backends

Description:
A common technique for distributing the burden of server load or storage space is called "sharding". When using this method, a front-end server will use the url to consistently "shard" users or objects to separate backend servers.
Solution:
A mapping is maintained, from users to target servers, in external map files. They look like:
user1 physical_host_of_user1user2 physical_host_of_user2: :
We put this into a map.users-to-hosts file. The aim is to map;
/u/user1/anypath
to
thus every URL path need not be valid on every backend physical host. The following ruleset does this for us with the help of the map files assuming that server0 is a default server which will be used if a user has no entry in the map:

RewriteEngine on RewriteMap users-to-hosts "txt:/path/to/map.users-to-hosts" RewriteRule "^/u/([^/]+)/?(.*)" "http://${users-to-hosts:$1%7Cserver0}/u/$1/$2"

See the RewriteMap documentation for more discussion of the syntax of this directive.

On-the-fly Content-Regeneration

Description:
We wish to dynamically generate content, but store it statically once it is generated. This rule will check for the existence of the static file, and if it's not there, generate it. The static files can be removed periodically, if desired (say, via cron) and will be regenerated on demand.
Solution:
This is done via the following ruleset:

# This example is valid in per-directory context only RewriteCond "%{REQUEST_URI}" "!-U" RewriteRule "^(.+)\.html$" "/regenerate_page.cgi" [PT,L]

The -U operator determines whether the test string (in this case, REQUEST_URI) is a valid URL. It does this via a subrequest. In the event that this subrequest fails - that is, the requested resource doesn't exist - this rule invokes the CGI program /regenerate_page.cgi, which generates the requested resource and saves it into the document directory, so that the next time it is requested, a static copy can be served.
In this way, documents that are infrequently updated can be served in static form. if documents need to be refreshed, they can be deleted from the document directory, and they will then be regenerated the next time they are requested.

Load Balancing

Description:
We wish to randomly distribute load across several servers using mod_rewrite.
Solution:
We'll use RewriteMap and a list of servers to accomplish this.

RewriteEngine on RewriteMap lb "rnd:/path/to/serverlist.txt" RewriteRule "^/(.*)" "http://${lb:servers}/$1" [P,L]

serverlist.txt will contain a list of the servers:
## serverlist.txtservers one.example.com|two.example.com|three.example.com
If you want one particular server to get more of the load than the others, add it more times to the list.
Discussion
Apache comes with a load-balancing module - mod_proxy_balancer - which is far more flexible and featureful than anything you can cobble together using mod_rewrite.

Structured Userdirs

Description:
Some sites with thousands of users use a structured homedir layout, i.e. each homedir is in a subdirectory which begins (for instance) with the first character of the username. So, /~larry/anypath is /home/l/larry/public_html/anypath while /~waldo/anypath is /home/w/waldo/public_html/anypath.
Solution:
We use the following ruleset to expand the tilde URLs into the above layout.

RewriteEngine on RewriteRule "^/~(([a-z])[a-z0-9]+)(.*)" "/home/$2/$1/public_html$3"

Redirecting Anchors

Description:
By default, redirecting to an HTML anchor doesn't work, because mod_rewrite escapes the # character, turning it into %23. This, in turn, breaks the redirection.
Solution:
Use the [NE] flag on the RewriteRule. NE stands for No Escape.
Discussion:
This technique will of course also work with other special characters that mod_rewrite, by default, URL-encodes.

Time-Dependent Rewriting

Description:
We wish to use mod_rewrite to serve different content based on the time of day.
Solution:
There are a lot of variables named TIME_xxx for rewrite conditions. In conjunction with the special lexicographic comparison patterns <STRING, >STRING and =STRING we can do time-dependent redirects:

RewriteEngine on RewriteCond "%{TIME_HOUR}%{TIME_MIN}" ">0700" RewriteCond "%{TIME_HOUR}%{TIME_MIN}" "<1900" RewriteRule "^foo\.html$" "foo.day.html" [L] RewriteRule "^foo\.html$" "foo.night.html"

This provides the content of foo.day.html under the URL foo.html from 07:01-18:59 and at the remaining time the contents of foo.night.html.
mod_cache, intermediate proxies and browsers may each cache responses and cause the either page to be shown outside of the time-window configured. mod_expires may be used to control this effect. You are, of course, much better off simply serving the content dynamically, and customizing it based on the time of day.

Set Environment Variables Based On URL Parts

Description:

At time, we want to maintain some kind of status when we perform a rewrite. For example, you want to make a note that you've done that rewrite, so that you can check later to see if a request can via that rewrite. One way to do this is by setting an environment variable.

Solution:

Use the [E] flag to set an environment variable.

RewriteEngine on RewriteRule "^/horse/(.*)" "/pony/$1" [E=rewritten:1]

Later in your ruleset you might check for this environment variable using a RewriteCond:

RewriteCond "%{ENV:rewritten}" "=1"

Note that environment variables do not survive an external redirect. You might consider using the [CO] flag to set a cookie.