1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
3 <?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
4 <!-- $LastChangedRevision$ -->
7 Licensed to the Apache Software Foundation (ASF) under one or more
8 contributor license agreements. See the NOTICE file distributed with
9 this work for additional information regarding copyright ownership.
10 The ASF licenses this file to You under the Apache License, Version 2.0
11 (the "License"); you may not use this file except in compliance with
12 the License. You may obtain a copy of the License at
14 http://www.apache.org/licenses/LICENSE-2.0
16 Unless required by applicable law or agreed to in writing, software
17 distributed under the License is distributed on an "AS IS" BASIS,
18 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 See the License for the specific language governing permissions and
20 limitations under the License.
23 <manualpage metafile="rewrite_guide.xml.meta">
24 <parentdocument href="./">Rewrite</parentdocument>
26 <title>URL Rewriting Guide</title>
30 <p>This document supplements the <module>mod_rewrite</module>
31 <a href="../mod/mod_rewrite.html">reference documentation</a>.
32 It describes how one can use Apache's <module>mod_rewrite</module>
33 to solve typical URL-based problems with which webmasters are
34 commonony confronted. We give detailed descriptions on how to
35 solve each problem by configuring URL rewriting rulesets.</p>
37 <note type="warning">ATTENTION: Depending on your server configuration
38 it may be necessary to slightly change the examples for your
39 situation, e.g. adding the <code>[PT]</code> flag when
40 additionally using <module>mod_alias</module> and
41 <module>mod_userdir</module>, etc. Or rewriting a ruleset
42 to fit in <code>.htaccess</code> context instead
43 of per-server context. Always try to understand what a
44 particular ruleset really does before you use it. This
45 avoids many problems.</note>
48 <seealso><a href="../mod/mod_rewrite.html">Module
49 documentation</a></seealso>
50 <seealso><a href="rewrite_intro.html">mod_rewrite
51 introduction</a></seealso>
52 <seealso><a href="rewrite_guide_advanced.html">Advanced Rewrite Guide - advanced
53 useful examples</a></seealso>
54 <seealso><a href="rewrite_tech.html">Technical details</a></seealso>
57 <section id="canonicalurl">
59 <title>Canonical URLs</title>
65 <p>On some webservers there are more than one URL for a
66 resource. Usually there are canonical URLs (which should be
67 actually used and distributed) and those which are just
68 shortcuts, internal ones, etc. Independent of which URL the
69 user supplied with the request he should finally see the
70 canonical one only.</p>
76 <p>We do an external HTTP redirect for all non-canonical
77 URLs to fix them in the location view of the Browser and
78 for all subsequent requests. In the example ruleset below
79 we replace <code>/~user</code> by the canonical
80 <code>/u/user</code> and fix a missing trailing slash for
81 <code>/u/user</code>.</p>
84 RewriteRule ^/<strong>~</strong>([^/]+)/?(.*) /<strong>u</strong>/$1/$2 [<strong>R</strong>]
85 RewriteRule ^/([uge])/(<strong>[^/]+</strong>)$ /$1/$2<strong>/</strong> [<strong>R</strong>]
92 <section id="canonicalhost"><title>Canonical Hostnames</title>
97 <dd>The goal of this rule is to force the use of a particular
98 hostname, in preference to other hostnames which may be used to
99 reach the same site. For example, if you wish to force the use
100 of <strong>www.example.com</strong> instead of
101 <strong>example.com</strong>, you might use a variant of the
102 following recipe.</dd>
107 <p>For sites running on a port other than 80:</p>
109 RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
110 RewriteCond %{HTTP_HOST} !^$
111 RewriteCond %{SERVER_PORT} !^80$
112 RewriteRule ^/(.*) http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]
115 <p>And for a site running on port 80</p>
117 RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
118 RewriteCond %{HTTP_HOST} !^$
119 RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
126 <section id="moveddocroot">
128 <title>Moved <code>DocumentRoot</code></title>
131 <dt>Description:</dt>
134 <p>Usually the <directive module="core">DocumentRoot</directive>
135 of the webserver directly relates to the URL "<code>/</code>".
136 But often this data is not really of top-level priority. For example,
137 you may wish for visitors, on first entering a site, to go to a
138 particular subdirectory <code>/about/</code>. This may be accomplished
139 using the following ruleset:</p>
145 <p>We redirect the URL <code>/</code> to
146 <code>/about/</code>:
151 RewriteRule <strong>^/$</strong> /about/ [<strong>R</strong>]
154 <p>Note that this can also be handled using the <directive
155 module="mod_alias">RedirectMatch</directive> directive:</p>
158 RedirectMatch ^/$ http://example.com/e/www/
165 <section id="trailingslash">
167 <title>Trailing Slash Problem</title>
170 <dt>Description:</dt>
172 <dd><p>The vast majority of "trailing slash" problems can be dealt
173 with using the techniques discussed in the <a
174 href="http://httpd.apache.org/docs/misc/FAQ-E.html#set-servername">FAQ
175 entry</a>. However, occasionally, there is a need to use mod_rewrite
176 to handle a case where a missing trailing slash causes a URL to
177 fail. This can happen, for example, after a series of complex
184 <p>The solution to this subtle problem is to let the server
185 add the trailing slash automatically. To do this
186 correctly we have to use an external redirect, so the
187 browser correctly requests subsequent images etc. If we
188 only did a internal rewrite, this would only work for the
189 directory page, but would go wrong when any images are
190 included into this page with relative URLs, because the
191 browser would request an in-lined object. For instance, a
192 request for <code>image.gif</code> in
193 <code>/~quux/foo/index.html</code> would become
194 <code>/~quux/image.gif</code> without the external
197 <p>So, to do this trick we write:</p>
202 RewriteRule ^foo<strong>$</strong> foo<strong>/</strong> [<strong>R</strong>]
205 <p>Alternately, you can put the following in a
206 top-level <code>.htaccess</code> file in the content directory.
207 But note that this creates some processing overhead.</p>
212 RewriteCond %{REQUEST_FILENAME} <strong>-d</strong>
213 RewriteRule ^(.+<strong>[^/]</strong>)$ $1<strong>/</strong> [R]
220 <section id="movehomedirs">
222 <title>Move Homedirs to Different Webserver</title>
225 <dt>Description:</dt>
228 <p>Many webmasters have asked for a solution to the
229 following situation: They wanted to redirect just all
230 homedirs on a webserver to another webserver. They usually
231 need such things when establishing a newer webserver which
232 will replace the old one over time.</p>
238 <p>The solution is trivial with <module>mod_rewrite</module>.
239 On the old webserver we just redirect all
240 <code>/~user/anypath</code> URLs to
241 <code>http://newserver/~user/anypath</code>.</p>
245 RewriteRule ^/~(.+) http://<strong>newserver</strong>/~$1 [R,L]
252 <section id="multipledirs">
254 <title>Search pages in more than one directory</title>
257 <dt>Description:</dt>
260 <p>Sometimes it is necessary to let the webserver search
261 for pages in more than one directory. Here MultiViews or
262 other techniques cannot help.</p>
268 <p>We program a explicit ruleset which searches for the
269 files in the directories.</p>
274 # first try to find it in dir1/...
275 # ...and if found stop and be happy:
276 RewriteCond /your/docroot/<strong>dir1</strong>/%{REQUEST_FILENAME} -f
277 RewriteRule ^(.+) /your/docroot/<strong>dir1</strong>/$1 [L]
279 # second try to find it in dir2/...
280 # ...and if found stop and be happy:
281 RewriteCond /your/docroot/<strong>dir2</strong>/%{REQUEST_FILENAME} -f
282 RewriteRule ^(.+) /your/docroot/<strong>dir2</strong>/$1 [L]
284 # else go on for other Alias or ScriptAlias directives,
286 RewriteRule ^(.+) - [PT]
293 <section id="setenvvars">
295 <title>Set Environment Variables According To URL Parts</title>
298 <dt>Description:</dt>
301 <p>Perhaps you want to keep status information between
302 requests and use the URL to encode it. But you don't want
303 to use a CGI wrapper for all pages just to strip out this
310 <p>We use a rewrite rule to strip out the status information
311 and remember it via an environment variable which can be
312 later dereferenced from within XSSI or CGI. This way a
313 URL <code>/foo/S=java/bar/</code> gets translated to
314 <code>/foo/bar/</code> and the environment variable named
315 <code>STATUS</code> is set to the value "java".</p>
319 RewriteRule ^(.*)/<strong>S=([^/]+)</strong>/(.*) $1/$3 [E=<strong>STATUS:$2</strong>]
326 <section id="uservhosts">
328 <title>Virtual User Hosts</title>
331 <dt>Description:</dt>
334 <p>Assume that you want to provide
335 <code>www.<strong>username</strong>.host.domain.com</code>
336 for the homepage of username via just DNS A records to the
337 same machine and without any virtualhosts on this
344 <p>For HTTP/1.0 requests there is no solution, but for
345 HTTP/1.1 requests which contain a Host: HTTP header we
346 can use the following ruleset to rewrite
347 <code>http://www.username.host.com/anypath</code>
348 internally to <code>/home/username/anypath</code>:</p>
352 RewriteCond %{<strong>HTTP_HOST</strong>} ^www\.<strong>[^.]+</strong>\.host\.com$
353 RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
354 RewriteRule ^www\.<strong>([^.]+)</strong>\.host\.com(.*) /home/<strong>$1</strong>$2
361 <section id="redirecthome">
363 <title>Redirect Homedirs For Foreigners</title>
366 <dt>Description:</dt>
369 <p>We want to redirect homedir URLs to another webserver
370 <code>www.somewhere.com</code> when the requesting user
371 does not stay in the local domain
372 <code>ourdomain.com</code>. This is sometimes used in
373 virtual host contexts.</p>
379 <p>Just a rewrite condition:</p>
383 RewriteCond %{REMOTE_HOST} <strong>!^.+\.ourdomain\.com$</strong>
384 RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
391 <section id="redirectanchors">
393 <title>Redirecting Anchors</title>
396 <dt>Description:</dt>
399 <p>By default, redirecting to an HTML anchor doesn't work,
400 because mod_rewrite escapes the <code>#</code> character,
401 turning it into <code>%23</code>. This, in turn, breaks the
408 <p>Use the <code>[NE]</code> flag on the
409 <code>RewriteRule</code>. NE stands for No Escape.
416 <section id="time-dependent">
418 <title>Time-Dependent Rewriting</title>
421 <dt>Description:</dt>
424 <p>When tricks like time-dependent content should happen a
425 lot of webmasters still use CGI scripts which do for
426 instance redirects to specialized pages. How can it be done
427 via <module>mod_rewrite</module>?</p>
433 <p>There are a lot of variables named <code>TIME_xxx</code>
434 for rewrite conditions. In conjunction with the special
435 lexicographic comparison patterns <code><STRING</code>,
436 <code>>STRING</code> and <code>=STRING</code> we can
437 do time-dependent redirects:</p>
441 RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
442 RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
443 RewriteRule ^foo\.html$ foo.day.html
444 RewriteRule ^foo\.html$ foo.night.html
447 <p>This provides the content of <code>foo.day.html</code>
448 under the URL <code>foo.html</code> from
449 <code>07:00-19:00</code> and at the remaining time the
450 contents of <code>foo.night.html</code>. Just a nice
451 feature for a homepage...</p>
457 <section id="backward-compatibility">
459 <title>Backward Compatibility for YYYY to XXXX migration</title>
462 <dt>Description:</dt>
465 <p>How can we make URLs backward compatible (still
466 existing virtually) after migrating <code>document.YYYY</code>
467 to <code>document.XXXX</code>, e.g. after translating a
468 bunch of <code>.html</code> files to <code>.phtml</code>?</p>
474 <p>We just rewrite the name to its basename and test for
475 existence of the new extension. If it exists, we take
476 that name, else we rewrite the URL to its original state.</p>
480 # backward compatibility ruleset for
481 # rewriting document.html to document.phtml
482 # when and only when document.phtml exists
483 # but no longer document.html
486 # parse out basename, but remember the fact
487 RewriteRule ^(.*)\.html$ $1 [C,E=WasHTML:yes]
488 # rewrite to document.phtml if exists
489 RewriteCond %{REQUEST_FILENAME}.phtml -f
490 RewriteRule ^(.*)$ $1.phtml [S=1]
491 # else reverse the previous basename cutout
492 RewriteCond %{ENV:WasHTML} ^yes$
493 RewriteRule ^(.*)$ $1.html
500 <section id="old-to-new">
502 <title>From Old to New (intern)</title>
505 <dt>Description:</dt>
508 <p>Assume we have recently renamed the page
509 <code>foo.html</code> to <code>bar.html</code> and now want
510 to provide the old URL for backward compatibility. Actually
511 we want that users of the old URL even not recognize that
512 the pages was renamed.</p>
518 <p>We rewrite the old URL to the new one internally via the
524 RewriteRule ^<strong>foo</strong>\.html$ <strong>bar</strong>.html
531 <section id="old-to-new-extern">
533 <title>From Old to New (extern)</title>
536 <dt>Description:</dt>
539 <p>Assume again that we have recently renamed the page
540 <code>foo.html</code> to <code>bar.html</code> and now want
541 to provide the old URL for backward compatibility. But this
542 time we want that the users of the old URL get hinted to
543 the new one, i.e. their browsers Location field should
550 <p>We force a HTTP redirect to the new URL which leads to a
551 change of the browsers and thus the users view:</p>
556 RewriteRule ^<strong>foo</strong>\.html$ <strong>bar</strong>.html [<strong>R</strong>]
563 <section id="static-to-dynamic">
565 <title>From Static to Dynamic</title>
568 <dt>Description:</dt>
571 <p>How can we transform a static page
572 <code>foo.html</code> into a dynamic variant
573 <code>foo.cgi</code> in a seamless way, i.e. without notice
574 by the browser/user.</p>
580 <p>We just rewrite the URL to the CGI-script and force the
581 handler to be <strong>cgi-script</strong> so that it is
582 executed as a CGI program.
583 This way a request to <code>/~quux/foo.html</code>
584 internally leads to the invocation of
585 <code>/~quux/foo.cgi</code>.</p>
590 RewriteRule ^foo\.<strong>html</strong>$ foo.<strong>cgi</strong> [H=<strong>cgi-script</strong>]
597 <section id="blocking-of-robots">
599 <title>Blocking of Robots</title>
602 <dt>Description:</dt>
605 <p>How can we block a really annoying robot from
606 retrieving pages of a specific webarea? A
607 <code>/robots.txt</code> file containing entries of the
608 "Robot Exclusion Protocol" is typically not enough to get
609 rid of such a robot.</p>
615 <p>We use a ruleset which forbids the URLs of the webarea
616 <code>/~quux/foo/arc/</code> (perhaps a very deep
617 directory indexed area where the robot traversal would
618 create big server load). We have to make sure that we
619 forbid access only to the particular robot, i.e. just
620 forbidding the host where the robot runs is not enough.
621 This would block users from this host, too. We accomplish
622 this by also matching the User-Agent HTTP header
626 RewriteCond %{HTTP_USER_AGENT} ^<strong>NameOfBadRobot</strong>.*
627 RewriteCond %{REMOTE_ADDR} ^<strong>123\.45\.67\.[8-9]</strong>$
628 RewriteRule ^<strong>/~quux/foo/arc/</strong>.+ - [<strong>F</strong>]
635 <section id="blocked-inline-images">
637 <title>Blocked Inline-Images</title>
640 <dt>Description:</dt>
643 <p>Assume we have under <code>http://www.quux-corp.de/~quux/</code>
644 some pages with inlined GIF graphics. These graphics are
645 nice, so others directly incorporate them via hyperlinks to
646 their pages. We don't like this practice because it adds
647 useless traffic to our server.</p>
653 <p>While we cannot 100% protect the images from inclusion,
654 we can at least restrict the cases where the browser
655 sends a HTTP Referer header.</p>
658 RewriteCond %{HTTP_REFERER} <strong>!^$</strong>
659 RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
660 RewriteRule <strong>.*\.gif$</strong> - [F]
664 RewriteCond %{HTTP_REFERER} !^$
665 RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
666 RewriteRule <strong>^inlined-in-foo\.gif$</strong> - [F]
673 <section id="proxy-deny">
675 <title>Proxy Deny</title>
678 <dt>Description:</dt>
681 <p>How can we forbid a certain host or even a user of a
682 special host from using the Apache proxy?</p>
688 <p>We first have to make sure <module>mod_rewrite</module>
689 is below(!) <module>mod_proxy</module> in the Configuration
690 file when compiling the Apache webserver. This way it gets
691 called <em>before</em> <module>mod_proxy</module>. Then we
692 configure the following for a host-dependent deny...</p>
695 RewriteCond %{REMOTE_HOST} <strong>^badhost\.mydomain\.com$</strong>
696 RewriteRule !^http://[^/.]\.mydomain.com.* - [F]
699 <p>...and this one for a user@host-dependent deny:</p>
702 RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>^badguy@badhost\.mydomain\.com$</strong>
703 RewriteRule !^http://[^/.]\.mydomain.com.* - [F]
710 <section id="external-rewriting">
712 <title>External Rewriting Engine</title>
715 <dt>Description:</dt>
718 <p>A FAQ: How can we solve the FOO/BAR/QUUX/etc.
719 problem? There seems no solution by the use of
720 <module>mod_rewrite</module>...</p>
726 <p>Use an external <directive module="mod_rewrite"
727 >RewriteMap</directive>, i.e. a program which acts
728 like a <directive module="mod_rewrite"
729 >RewriteMap</directive>. It is run once on startup of Apache
730 receives the requested URLs on <code>STDIN</code> and has
731 to put the resulting (usually rewritten) URL on
732 <code>STDOUT</code> (same order!).</p>
736 RewriteMap quux-map <strong>prg:</strong>/path/to/map.quux.pl
737 RewriteRule ^/~quux/(.*)$ /~quux/<strong>${quux-map:$1}</strong>
743 # disable buffered I/O which would lead
744 # to deadloops for the Apache server
747 # read URLs one per line from stdin and
748 # generate substitution URL on stdout
755 <p>This is a demonstration-only example and just rewrites
756 all URLs <code>/~quux/foo/...</code> to
757 <code>/~quux/bar/...</code>. Actually you can program
758 whatever you like. But notice that while such maps can be
759 <strong>used</strong> also by an average user, only the
760 system administrator can <strong>define</strong> it.</p>