1<?xml version="1.0" encoding="ISO-8859-1"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head><!--
4        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
5              This file is generated from xml source: DO NOT EDIT
6        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7      -->
8<title>Advanced Techniques with mod_rewrite - Apache HTTP Server</title>
9<link href="/style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" />
10<link href="/style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" />
11<link href="/style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="/style/css/prettify.css" />
12<script src="/style/scripts/prettify.min.js" type="text/javascript">
13</script>
14
15<link href="/images/favicon.ico" rel="shortcut icon" /></head>
16<body id="manual-page"><div id="page-header">
17<p class="menu"><a href="/mod/">Modules</a> | <a href="/mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="/glossary.html">Glossary</a> | <a href="/sitemap.html">Sitemap</a></p>
18<p class="apache">Apache HTTP Server Version 2.4</p>
19<img alt="" src="/images/feather.gif" /></div>
20<div class="up"><a href="./"><img title="&lt;-" alt="&lt;-" src="/images/left.gif" /></a></div>
21<div id="path">
22<a href="http://www.apache.org/">Apache</a> &gt; <a href="http://httpd.apache.org/">HTTP Server</a> &gt; <a href="http://httpd.apache.org/docs/">Documentation</a> &gt; <a href="../">Version 2.4</a> &gt; <a href="./">Rewrite</a></div><div id="page-content"><div id="preamble"><h1>Advanced Techniques with mod_rewrite</h1>
23<div class="toplang">
24<p><span>Available Languages: </span><a href="/en/rewrite/advanced.html" title="English">&nbsp;en&nbsp;</a> |
25<a href="/fr/rewrite/advanced.html" hreflang="fr" rel="alternate" title="Fran�ais">&nbsp;fr&nbsp;</a></p>
26</div>
27
28
29<p>This document supplements the <code class="module"><a href="/mod/mod_rewrite.html">mod_rewrite</a></code>
30<a href="/mod/mod_rewrite.html">reference documentation</a>. It provides
31a few advanced techniques using mod_rewrite.</p>
32
33<div class="warning">Note that many of these examples won't work unchanged in your
34particular server configuration, so it's important that you understand
35them, rather than merely cutting and pasting the examples into your
36configuration.</div>
37
38</div>
39<div id="quickview"><ul id="toc"><li><img alt="" src="/images/down.gif" /> <a href="#sharding">URL-based sharding accross multiple backends</a></li>
40<li><img alt="" src="/images/down.gif" /> <a href="#on-the-fly-content">On-the-fly Content-Regeneration</a></li>
41<li><img alt="" src="/images/down.gif" /> <a href="#load-balancing">Load Balancing</a></li>
42<li><img alt="" src="/images/down.gif" /> <a href="#autorefresh">Document With Autorefresh</a></li>
43<li><img alt="" src="/images/down.gif" /> <a href="#structuredhomedirs">Structured Userdirs</a></li>
44<li><img alt="" src="/images/down.gif" /> <a href="#redirectanchors">Redirecting Anchors</a></li>
45<li><img alt="" src="/images/down.gif" /> <a href="#time-dependent">Time-Dependent Rewriting</a></li>
46<li><img alt="" src="/images/down.gif" /> <a href="#setenvvars">Set Environment Variables Based On URL Parts</a></li>
47</ul><h3>See also</h3><ul class="seealso"><li><a href="/mod/mod_rewrite.html">Module documentation</a></li><li><a href="intro.html">mod_rewrite introduction</a></li><li><a href="remapping.html">Redirection and remapping</a></li><li><a href="access.html">Controlling access</a></li><li><a href="vhosts.html">Virtual hosts</a></li><li><a href="proxy.html">Proxying</a></li><li><a href="rewritemap.html">Using RewriteMap</a></li><li><a href="avoid.html">When not to use mod_rewrite</a></li></ul><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div>
48<div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
49<div class="section">
50<h2><a name="sharding" id="sharding">URL-based sharding accross multiple backends</a></h2>
51
52  
53
54  <dl>
55    <dt>Description:</dt>
56
57    <dd>
58      <p>A common technique for distributing the burden of
59      server load or storage space is called "sharding".
60      When using this method, a front-end server will use the
61      url to consistently "shard" users or objects to separate
62      backend servers.</p>
63    </dd>
64
65    <dt>Solution:</dt>
66
67    <dd>
68      <p>A mapping is maintained, from users to target servers, in
69      external map files. They look like:</p>
70
71<div class="example"><p><code>
72user1  physical_host_of_user1<br />
73user2  physical_host_of_user2<br />
74:      :
75</code></p></div>
76
77  <p>We put this into a <code>map.users-to-hosts</code> file. The
78    aim is to map;</p>
79
80<div class="example"><p><code>
81/u/user1/anypath
82</code></p></div>
83
84  <p>to</p>
85
86<div class="example"><p><code>
87http://physical_host_of_user1/u/user/anypath
88</code></p></div>
89
90      <p>thus every URL path need not be valid on every backend physical
91      host. The following ruleset does this for us with the help of the map
92      files assuming that server0 is a default server which will be used if
93      a user has no entry in the map:</p>
94
95<pre class="prettyprint lang-config">RewriteEngine on
96RewriteMap      users-to-hosts   txt:/path/to/map.users-to-hosts
97RewriteRule   ^/u/([^/]+)/?(.*)   http://${users-to-hosts:$1|server0}/u/$1/$2</pre>
98
99    </dd>
100  </dl>
101
102  <p>See the <code class="directive"><a href="/mod/mod_rewrite.html#rewritemap">RewriteMap</a></code>
103  documentation for more discussion of the syntax of this directive.</p>
104
105</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
106<div class="section">
107<h2><a name="on-the-fly-content" id="on-the-fly-content">On-the-fly Content-Regeneration</a></h2>
108
109  
110
111  <dl>
112    <dt>Description:</dt>
113
114    <dd>
115      <p>We wish to dynamically generate content, but store it
116      statically once it is generated. This rule will check for the
117      existence of the static file, and if it's not there, generate
118      it. The static files can be removed periodically, if desired (say,
119      via cron) and will be regenerated on demand.</p>
120    </dd>
121
122    <dt>Solution:</dt>
123
124    <dd>
125      This is done via the following ruleset:
126
127<pre class="prettyprint lang-config"># This example is valid in per-directory context only
128RewriteCond %{REQUEST_URI}   !-U
129RewriteRule ^(.+)\.html$          /regenerate_page.cgi   [PT,L]</pre>
130
131
132    <p>The <code>-U</code> operator determines whether the test string
133    (in this case, <code>REQUEST_URI</code>) is a valid URL. It does
134    this via a subrequest. In the event that this subrequest fails -
135    that is, the requested resource doesn't exist - this rule invokes
136    the CGI program <code>/regenerate_page.cgi</code>, which generates
137    the requested resource and saves it into the document directory, so
138    that the next time it is requested, a static copy can be served.</p>
139
140    <p>In this way, documents that are infrequently updated can be served in
141    static form. if documents need to be refreshed, they can be deleted
142    from the document directory, and they will then be regenerated the
143    next time they are requested.</p>
144    </dd>
145  </dl>
146
147</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
148<div class="section">
149<h2><a name="load-balancing" id="load-balancing">Load Balancing</a></h2>
150
151  
152
153  <dl>
154    <dt>Description:</dt>
155
156    <dd>
157      <p>We wish to randomly distribute load across several servers
158      using mod_rewrite.</p>
159    </dd>
160
161    <dt>Solution:</dt>
162
163    <dd>
164      <p>We'll use <code class="directive"><a href="/mod/mod_rewrite.html#rewritemap">RewriteMap</a></code> and a list of servers
165      to accomplish this.</p>
166
167<pre class="prettyprint lang-config">RewriteEngine on
168RewriteMap lb rnd:/path/to/serverlist.txt
169RewriteRule ^/(.*) http://${lb:servers}/$1 [P,L]</pre>
170
171
172<p><code>serverlist.txt</code> will contain a list of the servers:</p>
173
174<div class="example"><p><code>
175## serverlist.txt<br />
176<br />
177servers one.example.com|two.example.com|three.example.com<br />
178</code></p></div>
179
180<p>If you want one particular server to get more of the load than the
181others, add it more times to the list.</p>
182
183   </dd>
184
185   <dt>Discussion</dt>
186   <dd>
187<p>Apache comes with a load-balancing module -
188<code class="module"><a href="/mod/mod_proxy_balancer.html">mod_proxy_balancer</a></code> - which is far more flexible and
189featureful than anything you can cobble together using mod_rewrite.</p>
190   </dd>
191  </dl>
192
193</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
194<div class="section">
195<h2><a name="autorefresh" id="autorefresh">Document With Autorefresh</a></h2>
196
197  
198
199
200
201  <dl>
202    <dt>Description:</dt>
203
204    <dd>
205      <p>Wouldn't it be nice, while creating a complex web page, if
206      the web browser would automatically refresh the page every
207      time we save a new version from within our editor?
208      Impossible?</p>
209    </dd>
210
211    <dt>Solution:</dt>
212
213    <dd>
214      <p>No! We just combine the MIME multipart feature, the
215      web server NPH feature, and the URL manipulation power of
216      <code class="module"><a href="/mod/mod_rewrite.html">mod_rewrite</a></code>. First, we establish a new
217      URL feature: Adding just <code>:refresh</code> to any
218      URL causes the 'page' to be refreshed every time it is
219      updated on the filesystem.</p>
220
221<pre class="prettyprint lang-config">RewriteRule   ^(/[uge]/[^/]+/?.*):refresh  /internal/cgi/apache/nph-refresh?f=$1</pre>
222
223
224      <p>Now when we reference the URL</p>
225
226<div class="example"><p><code>
227/u/foo/bar/page.html:refresh
228</code></p></div>
229
230      <p>this leads to the internal invocation of the URL</p>
231
232<div class="example"><p><code>
233/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
234</code></p></div>
235
236      <p>The only missing part is the NPH-CGI script. Although
237      one would usually say "left as an exercise to the reader"
238      ;-) I will provide this, too.</p>
239
240<pre class="prettyprint lang-perl">#!/sw/bin/perl
241##
242##  nph-refresh -- NPH/CGI script for auto refreshing pages
243##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
244##
245$| = 1;
246
247#   split the QUERY_STRING variable
248@pairs = split( /&amp;/, $ENV{'QUERY_STRING'} );
249foreach $pair (@pairs) {
250    ( $name, $value ) = split( /=/, $pair );
251    $name =~ tr/A-Z/a-z/;
252    $name = 'QS_' . $name;
253    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
254    eval "\$$name = \"$value\"";
255}
256$QS_s = 1    if ( $QS_s eq '' );
257$QS_n = 3600 if ( $QS_n eq '' );
258if ( $QS_f eq '' ) {
259    print "HTTP/1.0 200 OK\n";
260    print "Content-type: text/html\n\n";
261    print "&lt;b&gt;ERROR&lt;/b&gt;: No file given\n";
262    exit(0);
263}
264if ( !-f $QS_f ) {
265    print "HTTP/1.0 200 OK\n";
266    print "Content-type: text/html\n\n";
267    print "&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n";
268    exit(0);
269}
270
271sub print_http_headers_multipart_begin {
272    print "HTTP/1.0 200 OK\n";
273    $bound = "ThisRandomString12345";
274    print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
275    &amp;print_http_headers_multipart_next;
276}
277
278sub print_http_headers_multipart_next {
279    print "\n--$bound\n";
280}
281
282sub print_http_headers_multipart_end {
283    print "\n--$bound--\n";
284}
285
286sub displayhtml {
287    local ($buffer) = @_;
288    $len = length($buffer);
289    print "Content-type: text/html\n";
290    print "Content-length: $len\n\n";
291    print $buffer;
292}
293
294sub readfile {
295    local ($file) = @_;
296    local ( *FP, $size, $buffer, $bytes );
297    ( $x, $x, $x, $x, $x, $x, $x, $size ) = stat($file);
298    $size = sprintf( "%d", $size );
299    open( FP, "&lt;$file" );
300    $bytes = sysread( FP, $buffer, $size );
301    close(FP);
302    return $buffer;
303}
304
305$buffer = &amp;readfile($QS_f);
306&amp;print_http_headers_multipart_begin;
307&amp;displayhtml($buffer);
308
309sub mystat {
310    local ($file) = $_[0];
311    local ($time);
312
313    ( $x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime ) = stat($file);
314    return $mtime;
315}
316
317$mtimeL = &amp;mystat($QS_f);
318$mtime  = $mtime;
319for ( $n = 0 ; $n &amp; lt ; $QS_n ; $n++ ) {
320    while (1) {
321        $mtime = &amp;mystat($QS_f);
322        if ( $mtime ne $mtimeL ) {
323            $mtimeL = $mtime;
324            sleep(2);
325            $buffer = &amp;readfile($QS_f);
326            &amp;print_http_headers_multipart_next;
327            &amp;displayhtml($buffer);
328            sleep(5);
329            $mtimeL = &amp;mystat($QS_f);
330            last;
331        }
332        sleep($QS_s);
333    }
334}
335
336&amp;print_http_headers_multipart_end;
337
338exit(0);
339
340##EOF##</pre>
341
342    </dd>
343  </dl>
344
345</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
346<div class="section">
347<h2><a name="structuredhomedirs" id="structuredhomedirs">Structured Userdirs</a></h2>
348
349  
350
351  <dl>
352    <dt>Description:</dt>
353
354    <dd>
355      <p>Some sites with thousands of users use a
356      structured homedir layout, <em>i.e.</em> each homedir is in a
357      subdirectory which begins (for instance) with the first
358      character of the username. So, <code>/~larry/anypath</code>
359      is <code>/home/<strong>l</strong>/larry/public_html/anypath</code>
360      while <code>/~waldo/anypath</code> is
361      <code>/home/<strong>w</strong>/waldo/public_html/anypath</code>.</p>
362    </dd>
363
364    <dt>Solution:</dt>
365
366    <dd>
367      <p>We use the following ruleset to expand the tilde URLs
368      into the above layout.</p>
369
370<pre class="prettyprint lang-config">RewriteEngine on
371RewriteRule   ^/~(<strong>([a-z])</strong>[a-z0-9]+)(.*)  /home/<strong>$2</strong>/$1/public_html$3</pre>
372
373    </dd>
374  </dl>
375
376</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
377<div class="section">
378<h2><a name="redirectanchors" id="redirectanchors">Redirecting Anchors</a></h2>
379
380  
381
382  <dl>
383    <dt>Description:</dt>
384
385    <dd>
386    <p>By default, redirecting to an HTML anchor doesn't work,
387    because mod_rewrite escapes the <code>#</code> character,
388    turning it into <code>%23</code>. This, in turn, breaks the
389    redirection.</p>
390    </dd>
391
392    <dt>Solution:</dt>
393
394    <dd>
395      <p>Use the <code>[NE]</code> flag on the
396      <code>RewriteRule</code>. NE stands for No Escape.
397      </p>
398    </dd>
399
400    <dt>Discussion:</dt>
401    <dd>This technique will of course also work with other
402    special characters that mod_rewrite, by default, URL-encodes.</dd>
403  </dl>
404
405</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
406<div class="section">
407<h2><a name="time-dependent" id="time-dependent">Time-Dependent Rewriting</a></h2>
408
409  
410
411  <dl>
412    <dt>Description:</dt>
413
414    <dd>
415      <p>We wish to use mod_rewrite to serve different content based on
416      the time of day.</p>
417    </dd>
418
419    <dt>Solution:</dt>
420
421    <dd>
422      <p>There are a lot of variables named <code>TIME_xxx</code>
423      for rewrite conditions. In conjunction with the special
424      lexicographic comparison patterns <code>&lt;STRING</code>,
425      <code>&gt;STRING</code> and <code>=STRING</code> we can
426      do time-dependent redirects:</p>
427
428<pre class="prettyprint lang-config">RewriteEngine on
429RewriteCond   %{TIME_HOUR}%{TIME_MIN} &gt;0700
430RewriteCond   %{TIME_HOUR}%{TIME_MIN} &lt;1900
431RewriteRule   ^foo\.html$             foo.day.html [L]
432RewriteRule   ^foo\.html$             foo.night.html</pre>
433
434
435      <p>This provides the content of <code>foo.day.html</code>
436      under the URL <code>foo.html</code> from
437      <code>07:01-18:59</code> and at the remaining time the
438      contents of <code>foo.night.html</code>.</p>
439
440      <div class="warning"><code class="module"><a href="/mod/mod_cache.html">mod_cache</a></code>, intermediate proxies
441      and browsers may each cache responses and cause the either page to be
442      shown outside of the time-window configured.
443      <code class="module"><a href="/mod/mod_expires.html">mod_expires</a></code> may be used to control this
444      effect. You are, of course, much better off simply serving the
445      content dynamically, and customizing it based on the time of day.</div>
446
447    </dd>
448  </dl>
449
450</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div>
451<div class="section">
452<h2><a name="setenvvars" id="setenvvars">Set Environment Variables Based On URL Parts</a></h2>
453
454  
455
456  <dl>
457    <dt>Description:</dt>
458
459    <dd>
460      <p>At time, we want to maintain some kind of status when we
461      perform a rewrite. For example, you want to make a note that
462      you've done that rewrite, so that you can check later to see if a
463      request can via that rewrite. One way to do this is by setting an
464      environment variable.</p>
465    </dd>
466
467    <dt>Solution:</dt>
468
469    <dd>
470      <p>Use the [E] flag to set an environment variable.</p>
471
472<pre class="prettyprint lang-config">RewriteEngine on
473RewriteRule   ^/horse/(.*)   /pony/$1 [E=<strong>rewritten:1</strong>]</pre>
474
475
476    <p>Later in your ruleset you might check for this environment
477    variable using a RewriteCond:</p>
478
479<pre class="prettyprint lang-config">RewriteCond %{ENV:rewritten} =1</pre>
480
481
482    <p>Note that environment variables do not survive an external
483    redirect. You might consider using the [CO] flag to set a
484    cookie.</p>
485
486    </dd>
487  </dl>
488
489</div></div>
490<div class="bottomlang">
491<p><span>Available Languages: </span><a href="/en/rewrite/advanced.html" title="English">&nbsp;en&nbsp;</a> |
492<a href="/fr/rewrite/advanced.html" hreflang="fr" rel="alternate" title="Fran�ais">&nbsp;fr&nbsp;</a></p>
493</div><div class="top"><a href="#page-header"><img src="/images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&amp;A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our <a href="http://httpd.apache.org/lists.html">mailing lists</a>.</div>
494<script type="text/javascript"><!--//--><![CDATA[//><!--
495var comments_shortname = 'httpd';
496var comments_identifier = 'http://httpd.apache.org/docs/2.4/rewrite/advanced.html';
497(function(w, d) {
498    if (w.location.hostname.toLowerCase() == "httpd.apache.org") {
499        d.write('<div id="comments_thread"><\/div>');
500        var s = d.createElement('script');
501        s.type = 'text/javascript';
502        s.async = true;
503        s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier;
504        (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s);
505    }
506    else { 
507        d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>');
508    }
509})(window, document);
510//--><!]]></script></div><div id="footer">
511<p class="apache">Copyright 2014 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
512<p class="menu"><a href="/mod/">Modules</a> | <a href="/mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="/glossary.html">Glossary</a> | <a href="/sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!--
513if (typeof(prettyPrint) !== 'undefined') {
514    prettyPrint();
515}
516//--><!]]></script>
517</body></html>