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="<-" alt="<-" src="/images/left.gif" /></a></div> 21<div id="path"> 22<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <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"> en </a> | 25<a href="/fr/rewrite/advanced.html" hreflang="fr" rel="alternate" title="Fran�ais"> fr </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( /&/, $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 "<b>ERROR</b>: 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 "<b>ERROR</b>: 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 &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, "<$file" ); 300 $bytes = sysread( FP, $buffer, $size ); 301 close(FP); 302 return $buffer; 303} 304 305$buffer = &readfile($QS_f); 306&print_http_headers_multipart_begin; 307&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 = &mystat($QS_f); 318$mtime = $mtime; 319for ( $n = 0 ; $n & lt ; $QS_n ; $n++ ) { 320 while (1) { 321 $mtime = &mystat($QS_f); 322 if ( $mtime ne $mtimeL ) { 323 $mtimeL = $mtime; 324 sleep(2); 325 $buffer = &readfile($QS_f); 326 &print_http_headers_multipart_next; 327 &displayhtml($buffer); 328 sleep(5); 329 $mtimeL = &mystat($QS_f); 330 last; 331 } 332 sleep($QS_s); 333 } 334} 335 336&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><STRING</code>, 425 <code>>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} >0700 430RewriteCond %{TIME_HOUR}%{TIME_MIN} <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"> en </a> | 492<a href="/fr/rewrite/advanced.html" hreflang="fr" rel="alternate" title="Fran�ais"> fr </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&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>