| <?xml version="1.0" encoding="UTF-8" ?> | |
| <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd"> | |
| <?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?> | |
| <!-- $LastChangedRevision$ --> | |
| <!-- | |
| Licensed to the Apache Software Foundation (ASF) under one or more | |
| contributor license agreements. See the NOTICE file distributed with | |
| this work for additional information regarding copyright ownership. | |
| The ASF licenses this file to You under the Apache License, Version 2.0 | |
| (the "License"); you may not use this file except in compliance with | |
| the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| --> | |
| <manualpage metafile="avoid.xml.meta"> | |
| <parentdocument href="./">Rewrite</parentdocument> | |
| <title>When not to use mod_rewrite</title> | |
| <summary> | |
| <p>This document supplements the <module>mod_rewrite</module> | |
| <a href="../mod/mod_rewrite.html">reference documentation</a>. It describes | |
| perhaps one of the most important concepts about <module>mod_rewrite</module> - namely, | |
| when to avoid using it.</p> | |
| <p><module>mod_rewrite</module> should be considered a last resort, when other | |
| alternatives are found wanting. Using it when there are simpler | |
| alternatives leads to configurations which are confusing, fragile, and | |
| hard to maintain. Understanding what other alternatives are available is | |
| a very important step towards <module>mod_rewrite</module> mastery.</p> | |
| <p>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.</p> | |
| <p>The most common situation in which <module>mod_rewrite</module> is | |
| the right tool is when the very best solution requires access to the | |
| server configuration files, and you don't have that access. Some | |
| configuration directives are only available in the server configuration | |
| file. So if you are in a hosting situation where you only have .htaccess | |
| files to work with, you may need to resort to | |
| <module>mod_rewrite</module>.</p> | |
| </summary> | |
| <seealso><a href="../mod/mod_rewrite.html">Module documentation</a></seealso> | |
| <seealso><a href="intro.html">mod_rewrite introduction</a></seealso> | |
| <seealso><a href="remapping.html">Redirection and remapping</a></seealso> | |
| <seealso><a href="htaccess.html">Per-directory Rewrites</a></seealso> | |
| <seealso><a href="flags.html">RewriteRule Flags</a></seealso> | |
| <seealso><a href="vhosts.html">Virtual hosts</a></seealso> | |
| <seealso><a href="rewritemap.html">Using RewriteMap</a></seealso> | |
| <seealso><a href="tech.html">Technical details</a></seealso> | |
| <section id="redirect"> | |
| <title>Simple Redirection</title> | |
| <p><module>mod_alias</module> provides the <directive | |
| module="mod_alias">Redirect</directive> and <directive | |
| module="mod_alias">RedirectMatch</directive> directives, which provide a | |
| means to redirect one URL to another. This kind of simple redirection of | |
| one URL, or a class of URLs, to somewhere else, should be accomplished | |
| using these directives rather than <directive | |
| module="mod_rewrite">RewriteRule</directive>. <code>RedirectMatch</code> | |
| allows you to include a regular expression in your redirection criteria, | |
| providing many of the benefits of using <code>RewriteRule</code>.</p> | |
| <p>A common use for <code>RewriteRule</code> is to redirect an entire | |
| class of URLs. For example, all URLs in the <code>/one</code> directory | |
| must be redirected to <code>http://one.example.com/</code>, or perhaps | |
| all <code>http</code> requests must be redirected to | |
| <code>https</code>.</p> | |
| <p>These situations are better handled by the <code>Redirect</code> | |
| directive. Remember that <code>Redirect</code> preserves path | |
| information. That is to say, a redirect for a URL <code>/one</code> will | |
| also redirect all URLs under that, such as <code>/one/two.html</code> | |
| and <code>/one/three/four.html</code>.</p> | |
| <p>To redirect URLs under <code>/one</code> to | |
| <code>http://one.example.com</code>, do the following:</p> | |
| <highlight language="config"> | |
| Redirect "/one/" "http://one.example.com/" | |
| </highlight> | |
| <p>To redirect one hostname to another, for example | |
| <code>example.com</code> to <code>www.example.com</code>, see the | |
| <a href="remapping.html#canonicalhost">Canonical Hostnames</a> | |
| recipe.</p> | |
| <p>To redirect <code>http</code> URLs to <code>https</code>, a | |
| <directive module="mod_alias">Redirect</directive> in a dedicated | |
| HTTP virtual host is the cleanest approach. See the | |
| <a href="remapping.html#https-redirect">Forcing HTTPS</a> recipe for | |
| the recommended configuration and the | |
| <module>mod_rewrite</module> alternative for <code>.htaccess</code> | |
| use.</p> | |
| <note><title>Processing order</title> | |
| <p>If you do mix <directive module="mod_alias">Redirect</directive> | |
| and <directive module="mod_rewrite">RewriteRule</directive> in the | |
| same context, be aware that their execution order depends on where | |
| they appear. In server/virtual-host context, | |
| <module>mod_rewrite</module> runs first; in per-directory context | |
| (<code>.htaccess</code>), <module>mod_alias</module> runs first. See | |
| <a href="tech.html#order">Module Processing Order</a> for | |
| details.</p> | |
| </note> | |
| </section> | |
| <section id="alias"><title>URL Aliasing</title> | |
| <p>The <directive module="mod_alias">Alias</directive> directive | |
| provides mapping from a URL-path to a directory - usually a directory outside | |
| of your <directive module="core">DocumentRoot</directive>. Although it | |
| is possible to perform this mapping with <module>mod_rewrite</module>, | |
| <directive module="mod_alias">Alias</directive> is the preferred method, for | |
| reasons of simplicity and performance.</p> | |
| <example><title>Using Alias</title> | |
| <highlight language="config"> | |
| Alias "/cats" "/var/www/virtualhosts/felines/htdocs" | |
| </highlight> | |
| </example> | |
| <p> | |
| The use of <module>mod_rewrite</module> to perform this mapping may be | |
| appropriate when you do not have access to the server configuration | |
| files. Alias may only be used in server or virtualhost context, and not | |
| in a <code>.htaccess</code> file. | |
| </p> | |
| <p>Symbolic links would be another way to accomplish the same thing, if | |
| you have <code>Options FollowSymLinks</code> enabled on your | |
| server.</p> | |
| </section> | |
| <section id="proxy"><title>Simple Proxying</title> | |
| <p><directive module="mod_rewrite">RewriteRule</directive> provides the <a | |
| href="flags.html#flag_p">[P]</a> flag to pass rewritten URIs through | |
| <module>mod_proxy</module>.</p> | |
| <highlight language="config"> | |
| RewriteRule "^/?images(.*)" "http://imageserver.local/images$1" [P] | |
| </highlight> | |
| <p>However, in many cases, when there is no actual pattern matching | |
| needed, as in the example shown above, the <directive | |
| module="mod_proxy">ProxyPass</directive> directive is a better choice. | |
| The example here could be rendered as:</p> | |
| <highlight language="config"> | |
| ProxyPass "/images/" "http://imageserver.local/images/" | |
| </highlight> | |
| <p>Note that whether you use <directive | |
| module="mod_rewrite">RewriteRule</directive> or <directive | |
| module="mod_proxy">ProxyPass</directive>, you'll still need to use the | |
| <directive module="mod_proxy">ProxyPassReverse</directive> directive to | |
| catch redirects issued from the back-end server:</p> | |
| <highlight language="config"> | |
| ProxyPassReverse "/images/" "http://imageserver.local/images/" | |
| </highlight> | |
| <p>You may need to use <code>RewriteRule</code> instead when there are | |
| other <code>RewriteRule</code>s in effect in the same scope, as a | |
| <code>RewriteRule</code> will usually take effect before a | |
| <code>ProxyPass</code>, and so may preempt what you're trying to | |
| accomplish.</p> | |
| <p>One case where <directive module="mod_rewrite">RewriteRule</directive> | |
| is genuinely useful for proxying is when you want to proxy requests only | |
| for content that doesn't exist locally - for example, during a migration | |
| from one server to another:</p> | |
| <highlight language="config"> | |
| RewriteCond "%{REQUEST_FILENAME}" !-f | |
| RewriteCond "%{REQUEST_FILENAME}" !-d | |
| RewriteRule "^/(.*)" "http://old.example.com/$1" [P] | |
| ProxyPassReverse "/" "http://old.example.com/" | |
| </highlight> | |
| <p>In this example, requests for resources that haven't been migrated | |
| yet are transparently proxied to the old server. As content is migrated, | |
| the local files take precedence. Remember to always include a | |
| <directive module="mod_proxy">ProxyPassReverse</directive> directive to | |
| ensure that any redirects issued by the backend are correctly passed on | |
| to the client.</p> | |
| </section> | |
| <section id="setenv"><title>Environment Variable Testing</title> | |
| <p><module>mod_rewrite</module> is frequently used to take a particular | |
| action based on the presence or absence of a particular environment | |
| variable or request header. This can be done more efficiently using the | |
| <directive module="core" type="section">If</directive> directive.</p> | |
| <p>Consider, for example, the common scenario where | |
| <directive>RewriteRule</directive> is used to enforce a canonical | |
| hostname, such as <code>www.example.com</code> instead of | |
| <code>example.com</code>. This can be done using the <directive | |
| module="core" type="section">If</directive> directive, as shown here:</p> | |
| <highlight language="config"> | |
| <If "req('Host') != 'www.example.com'"> | |
| Redirect "/" "http://www.example.com/" | |
| </If> | |
| </highlight> | |
| <p>This technique can be used to take actions based on any request | |
| header, response header, or environment variable, replacing | |
| <module>mod_rewrite</module> in many common scenarios.</p> | |
| <p>See especially the <a href="../expr.html">expression evaluation | |
| documentation</a> for a overview of what types of expressions you can | |
| use in <directive module="core" type="section">If</directive> sections, | |
| and in certain other directives.</p> | |
| </section> | |
| <section id="fallback-resource"><title>Front Controller / Resource Routing</title> | |
| <p>A very common use of <module>mod_rewrite</module> is to route all | |
| requests for non-existent resources to a single front controller script | |
| (e.g. <code>index.php</code>). This is the basis of most modern web | |
| framework routing.</p> | |
| <p>The typical <module>mod_rewrite</module> approach is:</p> | |
| <highlight language="config"> | |
| RewriteEngine On | |
| RewriteCond "%{REQUEST_FILENAME}" !-f | |
| RewriteCond "%{REQUEST_FILENAME}" !-d | |
| RewriteRule "^(.*)$" "/index.php" [L] | |
| </highlight> | |
| <p>This can be accomplished far more simply with the | |
| <directive module="mod_dir">FallbackResource</directive> directive:</p> | |
| <highlight language="config"> | |
| FallbackResource /index.php | |
| </highlight> | |
| <p><directive module="mod_dir">FallbackResource</directive> does the | |
| same thing - requests for existing files and directories are served | |
| normally, while everything else is routed to the specified resource - | |
| but without the overhead and complexity of the rewrite engine. It works | |
| in both server configuration and <code>.htaccess</code> context.</p> | |
| <p>To disable a <code>FallbackResource</code> set in a parent | |
| directory:</p> | |
| <highlight language="config"> | |
| FallbackResource disabled | |
| </highlight> | |
| </section> | |
| <section id="ifexpr"><title>Conditional Configuration with Expressions</title> | |
| <p>Many uses of <directive module="mod_rewrite">RewriteCond</directive> | |
| can be replaced by the | |
| <directive module="core" type="section">If</directive> directive, which | |
| supports a rich <a href="../expr.html">expression syntax</a> and | |
| integrates cleanly with other Apache directives.</p> | |
| <p>Redirect based on a query string parameter:</p> | |
| <highlight language="config"> | |
| <If "%{QUERY_STRING} =~ /lang=fr/"> | |
| Redirect "/welcome" "/bienvenue" | |
| </If> | |
| </highlight> | |
| <p>Restrict access by request method:</p> | |
| <highlight language="config"> | |
| <If "%{REQUEST_METHOD} IN {'DELETE', 'PUT', 'PATCH'}"> | |
| Require ip 10.0.0.0/8 | |
| </If> | |
| </highlight> | |
| <p>Block requests missing a Host header (HTTP/1.0 clients):</p> | |
| <highlight language="config"> | |
| <If "-z req('Host')"> | |
| Require all denied | |
| </If> | |
| </highlight> | |
| <p>See the <a href="../expr.html">expression evaluation | |
| documentation</a> for the full syntax available in | |
| <directive module="core" type="section">If</directive> blocks.</p> | |
| </section> | |
| <section id="blocked-inline-images"> | |
| <title>Forbidding Image Hotlinking</title> | |
| <dl> | |
| <dt>Description:</dt> | |
| <dd> | |
| <p>"Hotlinking" is the practice of other sites including your | |
| images inline in their pages, using your bandwidth to serve | |
| content for someone else's site. You can prevent this without | |
| <module>mod_rewrite</module>.</p> | |
| </dd> | |
| <dt>Solution:</dt> | |
| <dd> | |
| <p>Use <directive module="mod_setenvif">SetEnvIf</directive> | |
| with <directive module="mod_authz_core">Require</directive>:</p> | |
| <highlight language="config"> | |
| SetEnvIf Referer example\.com localreferer | |
| <FilesMatch "\.(jpg|png|gif)$"> | |
| Require env localreferer | |
| </FilesMatch> | |
| </highlight> | |
| </dd> | |
| <dt>Discussion:</dt> | |
| <dd> | |
| <p>If you need more complex logic - such as serving an | |
| alternate image to hotlinkers instead of denying the request - you | |
| may need <module>mod_rewrite</module>. The following examples | |
| rely on the <code>HTTP_REFERER</code> header, which is optional | |
| and can be spoofed. The <code>!^$</code> condition allows | |
| requests with no Referer header at all, so that users who type | |
| the URL directly, or whose browsers suppress the Referer, are | |
| not blocked.</p> | |
| <p>Deny the request outright:</p> | |
| <highlight language="config"> | |
| RewriteCond "%{HTTP_REFERER}" "!^$" | |
| RewriteCond "%{HTTP_REFERER}" "!www.example.com" [NC] | |
| RewriteRule "\.(gif|jpg|png)$" "-" [F,NC] | |
| </highlight> | |
| <p>Serve an alternate image:</p> | |
| <highlight language="config"> | |
| RewriteCond "%{HTTP_REFERER}" "!^$" | |
| RewriteCond "%{HTTP_REFERER}" "!www.example.com" [NC] | |
| RewriteRule "\.(gif|jpg|png)$" "/images/go-away.png" [R,NC] | |
| </highlight> | |
| </dd> | |
| </dl> | |
| </section> | |
| <section id="blocking-of-robots"> | |
| <title>Blocking of Robots</title> | |
| <dl> | |
| <dt>Description:</dt> | |
| <dd> | |
| <p>You wish to block persistent requests from a particular robot | |
| or user agent that ignores your <code>/robots.txt</code>.</p> | |
| </dd> | |
| <dt>Solution:</dt> | |
| <dd> | |
| <p>Use <directive module="mod_setenvif">SetEnvIfNoCase</directive> | |
| with <directive module="mod_authz_core">Require</directive>:</p> | |
| <highlight language="config"> | |
| SetEnvIfNoCase User-Agent ^NameOfBadRobot goaway | |
| <Location "/secret/files"> | |
| <RequireAll> | |
| Require all granted | |
| Require not env goaway | |
| </RequireAll> | |
| </Location> | |
| </highlight> | |
| </dd> | |
| <dt>Discussion:</dt> | |
| <dd> | |
| <p>Any technique that relies on the <code>USER_AGENT</code> | |
| string can be trivially circumvented, since that string can be | |
| changed by the client. If you are experiencing a sustained attack, | |
| you should consider blocking it at a higher level, such as at your | |
| firewall.</p> | |
| <p>If you need to combine user-agent and IP address matching, | |
| <module>mod_rewrite</module> can be used as a fallback:</p> | |
| <highlight language="config"> | |
| RewriteCond "%{HTTP_USER_AGENT}" "^NameOfBadRobot" | |
| RewriteCond "%{REMOTE_ADDR}" "=123\.45\.67\.[8-9]" | |
| RewriteRule "^/secret/files/" "-" [F] | |
| </highlight> | |
| </dd> | |
| </dl> | |
| </section> | |
| <section id="host-deny"> | |
| <title>Denying Hosts in a Reject List</title> | |
| <dl> | |
| <dt>Description:</dt> | |
| <dd> | |
| <p>We wish to maintain a list of hosts and have those hosts | |
| blocked from accessing our server.</p> | |
| </dd> | |
| <dt>Solution:</dt> | |
| <dd> | |
| <p>For simple IP-based blocking, use | |
| <directive module="mod_authz_host">Require</directive> directly:</p> | |
| <highlight language="config"> | |
| <Location "/"> | |
| <RequireAll> | |
| Require all granted | |
| Require not ip 193.102.180.41 | |
| Require not ip 192.76.162.40 | |
| </RequireAll> | |
| </Location> | |
| </highlight> | |
| </dd> | |
| <dt>Discussion:</dt> | |
| <dd> | |
| <p>If you need a dynamic, file-based deny list (rather than | |
| enumerating addresses in the configuration), <module>mod_rewrite</module> | |
| with a <directive module="mod_rewrite">RewriteMap</directive> | |
| can be used:</p> | |
| <highlight language="config"> | |
| RewriteEngine on | |
| RewriteMap hosts-deny "txt:/path/to/hosts.deny" | |
| RewriteCond "${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}" "!=NOT-FOUND" [OR] | |
| RewriteCond "${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}" "!=NOT-FOUND" | |
| RewriteRule "^" "-" [F] | |
| </highlight> | |
| <p>The map file contains one entry per line, with IP addresses or | |
| hostnames as keys and a dummy value (since | |
| <directive module="mod_rewrite">RewriteMap</directive> requires | |
| key/value pairs):</p> | |
| <example> | |
| ## hosts.deny<br /> | |
| 193.102.180.41 -<br /> | |
| 192.76.162.40 -<br /> | |
| </example> | |
| <p>The second <directive module="mod_rewrite">RewriteCond</directive> | |
| assumes <code>HostnameLookups</code> is enabled. If not, drop it | |
| and remove the <code>[OR]</code> flag from the first condition.</p> | |
| </dd> | |
| </dl> | |
| </section> | |
| <section id="vhosts"><title>Virtual Hosting</title> | |
| <p>Although it is possible to handle <a href="vhosts.html">virtual hosts | |
| with mod_rewrite</a>, it is seldom the right way. Creating individual | |
| <directive module="core" type="section">VirtualHost</directive> blocks is | |
| almost always the right way to go. In the | |
| event that you have an enormous number of virtual hosts, consider using | |
| <module>mod_vhost_alias</module> to create these hosts automatically.</p> | |
| <p>Modules such as <module>mod_macro</module> are | |
| also useful for creating a large number of virtual hosts dynamically.</p> | |
| <p>Using <module>mod_rewrite</module> for virtual host creation may be | |
| appropriate if you are using a hosting service that does not provide | |
| you access to the server configuration files, and you are therefore | |
| restricted to configuration using <code>.htaccess</code> files.</p> | |
| <p>See the <a href="vhosts.html">virtual hosts with mod_rewrite</a> | |
| document for more details on how you might accomplish this if it still | |
| seems like the right approach.</p> | |
| </section> | |
| <section id="load-balancing"> | |
| <title>Load Balancing</title> | |
| <dl> | |
| <dt>Description:</dt> | |
| <dd> | |
| <p>We wish to distribute load across several back-end | |
| servers.</p> | |
| </dd> | |
| <dt>Solution:</dt> | |
| <dd> | |
| <p>Use <module>mod_proxy_balancer</module>, which provides a | |
| flexible and featureful load-balancing solution. It supports | |
| several balancing algorithms, session stickiness, health checks, | |
| and dynamic configuration via the Balancer Manager - none of which | |
| are possible with a <module>mod_rewrite</module> approach.</p> | |
| <highlight language="config"> | |
| <Proxy "balancer://mycluster"> | |
| BalancerMember "http://one.example.com" | |
| BalancerMember "http://two.example.com" | |
| BalancerMember "http://three.example.com" | |
| </Proxy> | |
| ProxyPass "/" "balancer://mycluster/" | |
| ProxyPassReverse "/" "balancer://mycluster/" | |
| </highlight> | |
| </dd> | |
| <dt>Discussion:</dt> | |
| <dd> | |
| <p>It is possible to accomplish rudimentary random load balancing using | |
| <module>mod_rewrite</module> with a <code>rnd</code> | |
| <directive module="mod_rewrite">RewriteMap</directive>:</p> | |
| <highlight language="config"> | |
| RewriteEngine on | |
| RewriteMap lb "rnd:/path/to/serverlist.txt" | |
| RewriteRule "^/(.*)" "http://${lb:servers}/$1" [P,L] | |
| </highlight> | |
| <p>However, <module>mod_proxy_balancer</module> is far more flexible and | |
| featureful than anything you can cobble together using | |
| <module>mod_rewrite</module>, and is the recommended approach.</p> | |
| </dd> | |
| </dl> | |
| </section> | |
| </manualpage> |