Diskussion:Mod rewrite
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.
- %{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.
- %{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.
- %{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. - %{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. - %{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.
- 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). - 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. - 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] - 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:
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:
Security Warning
RewriteRule /file/(.*) http://localhost/tmp/$1
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:
In addition to plain text, the Substitution string can include# back-references ($N) to the RewriteRule pattern
- back-references (%N) to the last matched RewriteCond pattern
- server-variables as in rule condition test-strings (%{VARNAME})
- 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)
RewriteEngine on RewriteRule "^/foo\.html$" "bar.html" [R]
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
RewriteEngine on RewriteBase "/~quux/" RewriteRule "^foo\.html$" "foo.cgi" [H=cgi-script]
Backward Compatibility for file extension change
# 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>
Canonical Hostnames
<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>
<If "%{HTTP_HOST} != 'www.example.com'">
Redirect "/" "http://www.example.com/"
</If>
<If "%{SERVER_PROTOCOL} != 'HTTPS'">
Redirect "/admin/" "https://www.example.com/admin/"
</If>
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]
RewriteCond "%{HTTP_HOST}" "!^www\.example\.com" [NC] RewriteCond "%{HTTP_HOST}" "!^$" RewriteRule "^/?(.*)" "http://www.example.com/$1" [L,R,NE]
RewriteCond "%{HTTP_HOST}" "!^www\." [NC] RewriteCond "%{HTTP_HOST}" "!^$" RewriteRule "^/?(.*)" "http://www.%{HTTP_HOST}/$1" [L,R,NE]
Search for pages in more than one directory
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
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##
Browser Dependent Content
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.
RewriteRule "^/(puppies|canines)/(.*)" "/dogs/$2" [R]
RedirectMatch "^/(puppies|canines)/(.*)" "/dogs/$2"
Moved DocumentRoot
RewriteEngine on RewriteRule "^/$" "/about/" [R]
RedirectMatch "^/$" "http://example.com/about/"
Fallback Resource
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.
<Directory "/var/www/my_blog">
FallbackResource "index.php"
</Directory>
<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>
RewriteRule "(.*)" "index.php?$1" [PT,QSA]
Rewrite query string
* 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;
- Substitution: where should the matching requests be sent;
- [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:
RewriteRule "^/games" "/usr/local/games/web"
RewriteRule "^/foo$" "/bar"
RewriteRule "^/product/view$" "http://site2.example.com/seeproduct.html" [R]
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.
You may optionally also set the following values:
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
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
# This example is valid in per-directory context only RewriteCond "%{REQUEST_URI}" "!-U" RewriteRule "^(.+)\.html$" "/regenerate_page.cgi" [PT,L]
Load Balancing
RewriteEngine on RewriteMap lb "rnd:/path/to/serverlist.txt" RewriteRule "^/(.*)" "http://${lb:servers}/$1" [P,L]
Structured Userdirs
RewriteEngine on RewriteRule "^/~(([a-z])[a-z0-9]+)(.*)" "/home/$2/$1/public_html$3"
Redirecting Anchors
Time-Dependent Rewriting
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"
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:
RewriteEngine on RewriteRule "^/horse/(.*)" "/pony/$1" [E=rewritten:1]
RewriteCond "%{ENV:rewritten}" "=1"