]> granicus.if.org Git - apache/blob - docs/manual/rewrite/remapping.xml
Encourage people to use Redirect rather than mod_rewrite.
[apache] / docs / manual / rewrite / remapping.xml
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$ -->
5
6 <!--
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
13
14      http://www.apache.org/licenses/LICENSE-2.0
15
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.
21 -->
22
23 <manualpage metafile="remapping.xml.meta">
24   <parentdocument href="./">Rewrite</parentdocument>
25
26 <title>Redirecting and Remapping with mod_rewrite</title>
27
28 <summary>
29
30 <p>This document supplements the <module>mod_rewrite</module> 
31 <a href="../mod/mod_rewrite.html">reference documentation</a>. It describes
32 how you can use <module>mod_rewrite</module> to redirect and remap
33 request. This includes many examples of common uses of mod_rewrite,
34 including detailed descriptions of how each works.</p>
35
36 <note type="warning">Note that many of these examples won't work unchanged in your
37 particular server configuration, so it's important that you understand
38 them, rather than merely cutting and pasting the examples into your
39 configuration.</note>
40
41 </summary>
42 <seealso><a href="../mod/mod_rewrite.html">Module documentation</a></seealso>
43 <seealso><a href="intro.html">mod_rewrite introduction</a></seealso>
44 <!--<seealso><a href="remapping.html">Redirection and remapping</a></seealso>-->
45 <seealso><a href="access.html">Controlling access</a></seealso>
46 <seealso><a href="vhosts.html">Virtual hosts</a></seealso>
47 <seealso><a href="proxy.html">Proxying</a></seealso>
48 <seealso><a href="advanced.html">Advanced techniques and tricks</a></seealso>
49 <seealso><a href="avoid.html">When not to use mod_rewrite</a></seealso>
50
51 <section id="old-to-new">
52
53   <title>From Old to New (internal)</title>
54
55   <dl>
56     <dt>Description:</dt>
57
58     <dd>
59       <p>Assume we have recently renamed the page
60       <code>foo.html</code> to <code>bar.html</code> and now want
61       to provide the old URL for backward compatibility. However,
62       we want that users of the old URL even not recognize that
63       the pages was renamed - that is, we don't want the address to
64       change in their browser.</p>
65     </dd>
66
67     <dt>Solution:</dt>
68
69     <dd>
70       <p>We rewrite the old URL to the new one internally via the
71       following rule:</p>
72
73 <example><pre>
74 RewriteEngine  on
75 RewriteRule    ^<strong>/old</strong>\.html$  <strong>/new</strong>.html [PT]
76 </pre></example>
77     </dd>
78   </dl>
79
80 </section>
81
82 <section id="old-to-new-extern">
83
84   <title>Rewriting From Old to New (external)</title>
85
86   <dl>
87     <dt>Description:</dt>
88
89     <dd>
90       <p>Assume again that we have recently renamed the page
91       <code>foo.html</code> to <code>bar.html</code> and now want
92       to provide the old URL for backward compatibility. But this
93       time we want that the users of the old URL get hinted to
94       the new one, i.e. their browsers Location field should
95       change, too.</p>
96     </dd>
97
98     <dt>Solution:</dt>
99
100     <dd>
101       <p>We force a HTTP redirect to the new URL which leads to a
102       change of the browsers and thus the users view:</p>
103
104 <example><pre>
105 RewriteEngine  on
106 RewriteRule    ^<strong>/foo</strong>\.html$  <strong>bar</strong>.html  [<strong>R</strong>]
107 </pre></example>
108 </dd>
109
110 <dt>Discussion</dt>
111
112     <dd>
113     <p>In this example, as contrasted to the <a
114     href="#old-to-new-intern">internal</a> example above, we can simply
115     use the Redirect directive. mod_rewrite was used in that earlier
116     example in order to hide the redirect from the client:</p>
117
118     <example>
119     Redirect /foo.html /bar.html
120     </example>
121
122     </dd>
123   </dl>
124
125 </section>
126
127 <section id="movehomedirs">
128
129   <title>Resource Moved to Another Server</title>
130
131   <dl>
132     <dt>Description:</dt>
133
134     <dd>
135       <p>If a resource has moved to another server, you may wish to have
136       URLs continue to work for a time on the old server while people
137       update their bookmarks.</p>
138     </dd>
139
140     <dt>Solution:</dt>
141
142     <dd>
143       <p>You can use <module>mod_rewrite</module> to redirect these URLs
144       to the new server, but you might also consider using the Redirect
145       or RedirectMatch directive.</p>
146
147 <example><title>With mod_rewrite</title><pre>
148 RewriteEngine on
149 RewriteRule   ^/docs/(.+)  http://new.example.com/docs/$1  [R,L]
150 </pre></example>
151
152 <example><title>With RedirectMatch</title><pre>
153 RedirectMatch ^/docs/(.*) http://new.example.com/docs/$1
154 </pre></example>
155
156 <example><title>With Redirect</title><pre>
157 Redirect /docs/ http://new.example.com/docs/
158 </pre></example>
159     </dd>
160   </dl>
161
162 </section>
163
164 <section id="static-to-dynamic">
165
166   <title>From Static to Dynamic</title>
167
168   <dl>
169     <dt>Description:</dt>
170
171     <dd>
172       <p>How can we transform a static page
173       <code>foo.html</code> into a dynamic variant
174       <code>foo.cgi</code> in a seamless way, i.e. without notice
175       by the browser/user.</p>
176     </dd>
177
178     <dt>Solution:</dt>
179
180     <dd>
181       <p>We just rewrite the URL to the CGI-script and force the
182       handler to be <strong>cgi-script</strong> so that it is
183       executed as a CGI program.
184       This way a request to <code>/~quux/foo.html</code>
185       internally leads to the invocation of
186       <code>/~quux/foo.cgi</code>.</p>
187
188 <example><pre>
189 RewriteEngine  on
190 RewriteBase    /~quux/
191 RewriteRule    ^foo\.<strong>html</strong>$  foo.<strong>cgi</strong>  [H=<strong>cgi-script</strong>]
192 </pre></example>
193     </dd>
194   </dl>
195
196 </section>
197
198 <section id="backward-compatibility">
199
200   <title>Backward Compatibility for file extension change</title>
201
202   <dl>
203     <dt>Description:</dt>
204
205     <dd>
206       <p>How can we make URLs backward compatible (still
207       existing virtually) after migrating <code>document.YYYY</code>
208       to <code>document.XXXX</code>, e.g. after translating a
209       bunch of <code>.html</code> files to <code>.php</code>?</p>
210     </dd>
211
212     <dt>Solution:</dt>
213
214     <dd>
215       <p>We rewrite the name to its basename and test for
216       existence of the new extension. If it exists, we take
217       that name, else we rewrite the URL to its original state.</p>
218
219 <example><pre>
220 #   backward compatibility ruleset for
221 #   rewriting document.html to document.php
222 #   when and only when document.php exists
223 &lt;Directory /var/www/htdocs&gt;
224 RewriteEngine on
225 RewriteBase /var/www/htdocs
226
227 RewriteCond $1.php -f
228 RewriteCond $1.html !-f
229 RewriteRule ^(.*).html$ $1.php
230 &lt;/Directory&gt;
231 </pre></example>
232     </dd>
233
234     <dt>Discussion</dt>
235     <dd>
236     <p>This example uses an often-overlooked feature of mod_rewrite,
237     by taking advantage of the order of execution of the ruleset. In
238     particular, mod_rewrite evaluates the left-hand-side of the
239     RewriteRule before it evaluates the RewriteCond directives.
240     Consequently, $1 is already defined by the time the RewriteCond
241     directives are evaluated. This allows us to test for the existence
242     of the original (<code>document.html</code>) and target
243     (<code>document.php</code>) files using the same base filename.</p>
244
245     <p>This ruleset is designed to use in a per-directory context (In a
246     &lt;Directory&gt; block or in a .htaccess file), so that the
247     <code>-f</code> checks are looking at the correct directory path.
248     You may need to set a <directive
249     module="mod_rewite">RewriteBase</directive> directive to specify the
250     directory base that you're working in.</p>
251     </dd>
252   </dl>
253
254 </section>
255
256 <section id="canonicalhost">
257
258 <title>Canonical Hostnames</title>
259
260       <dl>
261         <dt>Description:</dt>
262
263         <dd>The goal of this rule is to force the use of a particular
264         hostname, in preference to other hostnames which may be used to
265         reach the same site. For example, if you wish to force the use
266         of <strong>www.example.com</strong> instead of
267         <strong>example.com</strong>, you might use a variant of the
268         following recipe.</dd>
269
270         <dt>Solution:</dt>
271
272         <dd>
273
274 <p>The very best way to solve this doesn't involve mod_rewrite at all,
275 but rather uses the <directive module="alias">Redirect</directive>
276 directive places in a virtual host for the non-canonical
277 hostname(s).</p>
278
279 <example><pre>
280 &lt;VirtualHost *:80&gt;
281   ServerName undesired.example.com
282   ServerAlias example.com notthis.example.com
283
284   Redirect / http://www.example.com/
285 &lt;/VirtualHost&gt;
286 </pre></example>
287
288 <p>However, there are situations where you'll need to use mod_rewrite -
289 primarily when you don't have access to the main server configuration
290 file, or if you wish to do this dynamically for a larger number of
291 hostnames. For these situations, you might use one of the recipes
292 below.</p>
293
294 <p>For sites running on a port other than 80:</p>
295 <example><pre>
296 RewriteCond %{HTTP_HOST}   !^www\.example\.com [NC]
297 RewriteCond %{HTTP_HOST}   !^$
298 RewriteCond %{SERVER_PORT} !^80$
299 RewriteRule ^/?(.*)         http://www.example.com:%{SERVER_PORT}/$1 [L,R,NE]
300 </pre></example>
301
302 <p>And for a site running on port 80</p>
303 <example><pre>
304 RewriteCond %{HTTP_HOST}   !^www\.example\.com [NC]
305 RewriteCond %{HTTP_HOST}   !^$
306 RewriteRule ^/?(.*)         http://www.example.com/$1 [L,R,NE]
307 </pre></example>
308
309         <p>
310         If you wanted to do this generically for all domain names - that
311         is, if you want to redirect <strong>example.com</strong> to
312         <strong>www.example.com</strong> for all possible values of
313         <strong>example.com</strong>, you could use the following
314         recipe:</p>
315
316 <example><pre>
317 RewriteCond %{HTTP_HOST} !^www\. [NC]
318 RewriteCond %{HTTP_HOST} !^$
319 RewriteRule ^/?(.*) http://www.%{HTTP_HOST}/$1 [L,R,NE]
320 </pre></example>
321
322     <p>These rulesets will work either in your main server configuration
323     file, or in a <code>.htaccess</code> file placed in the <directive
324     module="core">DocumentRoot</directive> of the server.</p>
325         </dd>
326       </dl>
327
328 </section>
329
330 <section id="multipledirs">
331
332   <title>Search for pages in more than one directory</title>
333
334   <dl>
335     <dt>Description:</dt>
336
337     <dd>
338       <p>A particular resource might exist in one of several places, and
339       we want to look in those places for the resource when it is
340       requested. Perhaps we've recently rearranged our directory
341       structure, dividing content into several locations.</p>
342     </dd>
343
344     <dt>Solution:</dt>
345
346     <dd>
347       <p>The following ruleset searches in two directories to find the
348       resource, and, if not finding it in either place, will attempt to
349       just serve it out of the location requested.</p>
350
351 <example><pre>
352 RewriteEngine on
353
354 #   first try to find it in dir1/...
355 #   ...and if found stop and be happy:
356 RewriteCond         %{DOCUMENT_ROOT}/<strong>dir1</strong>/%{REQUEST_URI}  -f
357 RewriteRule  ^(.+)  %{DOCUMENT_ROOT}/<strong>dir1</strong>/$1  [L]
358
359 #   second try to find it in dir2/...
360 #   ...and if found stop and be happy:
361 RewriteCond         %{DOCUMENT_ROOT}/<strong>dir2</strong>/%{REQUEST_URI}  -f
362 RewriteRule  ^(.+)  %{DOCUMENT_ROOT}/<strong>dir2</strong>/$1  [L]
363
364 #   else go on for other Alias or ScriptAlias directives,
365 #   etc.
366 RewriteRule   ^  -  [PT]
367 </pre></example>
368     </dd>
369   </dl>
370
371 </section>
372
373 <section id="archive-access-multiplexer">
374
375   <title>Redirecting to Geographically Distributed Servers</title>
376
377   <dl>
378     <dt>Description:</dt>
379
380     <dd>
381     <p>We have numerous mirrors of our website, and want to redirect
382     people to the one that is located in the country where they are
383     located.</p>
384     </dd>
385
386     <dt>Solution:</dt>
387
388     <dd>
389     <p>Looking at the hostname of the requesting client, we determine
390     which country they are coming from. If we can't do a lookup on their
391     IP address, we fall back to a default server.</p>
392     <p>We'll use a <directive module="mod_rewrite">RewriteMap</directive>
393     directive to build a list of servers that we wish to use.</p>
394
395 <example><pre>
396 HostnameLookups on
397 RewriteEngine on
398 RewriteMap    multiplex         txt:/path/to/map.mirrors
399 RewriteCond  %{REMOTE_HOST}     ([a-z]+)$ [NC]
400 RewriteRule   ^/(.*)$  ${multiplex:<strong>%1</strong>|http://www.example.com/}$1  [R,L]
401 </pre></example>
402
403 <example><pre>
404 ##  map.mirrors -- Multiplexing Map
405
406 de        http://www.example.de/
407 uk        http://www.example.uk/
408 com       http://www.example.com/
409 ##EOF##
410 </pre></example>
411     </dd>
412
413     <dt>Discussion</dt>
414     <dd>
415     <note type="warning">This ruleset relies on 
416     <directive module="core">HostNameLookups</directive> 
417     being set <code>on</code>, which can be
418     a significant performance hit.</note>
419
420     <p>The <directive module="mod_rewrite">RewriteCond</directive>
421     directive captures the last portion of the hostname of the
422     requesting client - the country code - and the following RewriteRule
423     uses that value to look up the appropriate mirror host in the map
424     file.</p>
425     </dd>
426   </dl>
427
428 </section>
429
430 <section id="browser-dependent-content">
431
432   <title>Browser Dependent Content</title>
433
434   <dl>
435     <dt>Description:</dt>
436
437     <dd>
438       <p>We wish to provide different content based on the browser, or
439       user-agent, which is requesting the content.</p>
440     </dd>
441
442     <dt>Solution:</dt>
443
444     <dd>
445       <p>We have to decide, based on the HTTP header "User-Agent",
446       which content to serve. The following config
447       does the following: If the HTTP header "User-Agent"
448       contains "Mozilla/3", the page <code>foo.html</code>
449       is rewritten to <code>foo.NS.html</code> and the
450       rewriting stops. If the browser is "Lynx" or "Mozilla" of
451       version 1 or 2, the URL becomes <code>foo.20.html</code>.
452       All other browsers receive page <code>foo.32.html</code>.
453       This is done with the following ruleset:</p>
454
455 <example><pre>
456 RewriteCond %{HTTP_USER_AGENT}  ^<strong>Mozilla/3</strong>.*
457 RewriteRule ^foo\.html$         foo.<strong>NS</strong>.html          [<strong>L</strong>]
458
459 RewriteCond %{HTTP_USER_AGENT}  ^<strong>Lynx/</strong>.*         [OR]
460 RewriteCond %{HTTP_USER_AGENT}  ^<strong>Mozilla/[12]</strong>.*
461 RewriteRule ^foo\.html$         foo.<strong>20</strong>.html          [<strong>L</strong>]
462
463 RewriteRule ^foo\.html$         foo.<strong>32</strong>.html          [<strong>L</strong>]
464 </pre></example>
465     </dd>
466   </dl>
467
468 </section>
469
470 <section id="canonicalurl">
471
472 <title>Canonical URLs</title>
473
474 <dl>
475  <dt>Description:</dt>
476
477    <dd>
478      <p>On some webservers there is more than one URL for a
479      resource. Usually there are canonical URLs (which are be
480      actually used and distributed) and those which are just
481      shortcuts, internal ones, and so on. Independent of which URL the
482      user supplied with the request, they should finally see the
483      canonical one in their browser address bar.</p>
484    </dd>
485
486    <dt>Solution:</dt>
487
488      <dd>
489        <p>We do an external HTTP redirect for all non-canonical
490        URLs to fix them in the location view of the Browser and
491        for all subsequent requests. In the example ruleset below
492        we replace <code>/puppies</code> and <code>/canines</code>
493        by the canonical <code>/dogs</code>.</p>
494
495 <example><pre>
496 RewriteRule   ^/(puppies|canines)/(.*)    /dogs/$2  [R]
497 </pre></example>
498         </dd>
499
500      <dt>Discussion:</dt>
501      <dd>
502      This should really be accomplished with Redirect or RedirectMatch
503      directives:
504
505      <example><pre>
506      RedirectMatch ^/(puppies|canines)/(.*) /dogs/$2
507      </pre></example>
508      </dd>
509       </dl>
510
511 </section>
512
513 <section id="moveddocroot">
514
515   <title>Moved <code>DocumentRoot</code></title>
516
517   <dl>
518     <dt>Description:</dt>
519
520     <dd>
521 <p>Usually the <directive module="core">DocumentRoot</directive>
522 of the webserver directly relates to the URL "<code>/</code>".
523 But often this data is not really of top-level priority. For example,
524 you may wish for visitors, on first entering a site, to go to a
525 particular subdirectory <code>/about/</code>. This may be accomplished
526 using the following ruleset:</p>
527 </dd>
528
529     <dt>Solution:</dt>
530
531     <dd>
532       <p>We redirect the URL <code>/</code> to
533       <code>/about/</code>:
534       </p>
535      
536 <example><pre>
537 RewriteEngine on
538 RewriteRule   <strong>^/$</strong>  /about/  [<strong>R</strong>]
539 </pre></example>
540
541 <p>Note that this can also be handled using the <directive
542 module="mod_alias">RedirectMatch</directive> directive:</p>
543
544 <example>
545 RedirectMatch ^/$ http://example.com/about/
546 </example>
547
548 <p>Note also that the example rewrites only the root URL. That is, it
549 rewrites a request for <code>http://example.com/</code>, but not a
550 request for <code>http://example.com/page.html</code>. If you have in 
551 fact changed your document root - that is, if <strong>all</strong> of 
552 your content is in fact in that subdirectory, it is greatly preferable 
553 to simply change your <directive module="core">DocumentRoot</directive>
554 directive, or move all of the content up one directory,
555 rather than rewriting URLs.</p>
556 </dd>
557 </dl>
558
559 </section>
560
561 <section id="fallback-resource">
562 <title>Fallback Resource</title>
563
564 <dl>
565 <dt>Description:</dt>
566 <dd>You want a single resource (say, a certain file, like index.php) to
567 handle all requests that come to a particular directory, except those
568 that should go to an existing resource such as an image, or a css file.</dd>
569
570 <dt>Solution:</dt>
571 <dd>
572 <p>As of version 2.4, you should use the <directive
573 module="mod_dir">FallbackResource</directive> directive for this:</p>
574
575 <example>
576 <pre>
577 &lt;Directory /var/www/my_blog&gt;
578   FallbackResource index.php
579 &lt;/Directory&gt;
580 </pre>
581 </example>
582
583 <p>However, in earlier versions of Apache, or if your needs are more
584 complicated than this, you can use a variation of the following rewrite
585 set to accomplish the same thing:</p>
586
587 <example>
588 <pre>
589 &lt;Directory /var/www/my_blog&gt;
590   RewriteBase /my_blog
591
592   RewriteCond /var/www/my_blog/%{REQUEST_FILENAME} !-f
593   RewriteCond /var/www/my_blog/%{REQUEST_FILENAME} !-d
594   RewriteRule ^ index.php [PT]
595 &lt;/Directory&gt;
596 </pre>
597 </example>
598
599 <p>If, on the other hand, you wish to pass the requested URI as a query
600 string argument to index.php, you can replace that RewriteRule with:</p>
601
602 <example>
603 <pre>
604   RewriteRule (.*) index.php?$1 [PT,QSA]
605 </pre>
606 </example>
607
608 <p>Note that these rulesets can be uses in a <code>.htaccess</code>
609 file, as well as in a &lt;Directory&gt; block.</p>
610
611 </dd>
612
613 </dl>
614
615 </section>
616
617 </manualpage>