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
8
<title>URL Rewriting Guide - Advanced topics - 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" />
12
<link href="../images/favicon.ico" rel="shortcut icon" /></head>
13
<body id="manual-page"><div id="page-header">
14
<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p>
15
<p class="apache">Apache HTTP Server Version 2.2</p>
16
<img alt="" src="../images/feather.gif" /></div>
17
<div class="up"><a href="./index.html"><img title="<-" alt="<-" src="../images/left.gif" /></a></div>
19
<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.2</a></div><div id="page-content"><div id="preamble"><h1>URL Rewriting Guide - Advanced topics</h1>
21
<p><span>Available Languages: </span><a href="../en/rewrite/rewrite_guide_advanced.html" title="English"> en </a></p>
25
<p>This document supplements the <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>
26
<a href="../mod/mod_rewrite.html">reference documentation</a>.
27
It describes how one can use Apache's <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>
28
to solve typical URL-based problems with which webmasters are
29
commonony confronted. We give detailed descriptions on how to
30
solve each problem by configuring URL rewriting rulesets.</p>
32
<div class="warning">ATTENTION: Depending on your server configuration
33
it may be necessary to slightly change the examples for your
34
situation, e.g. adding the <code>[PT]</code> flag when
35
additionally using <code class="module"><a href="../mod/mod_alias.html">mod_alias</a></code> and
36
<code class="module"><a href="../mod/mod_userdir.html">mod_userdir</a></code>, etc. Or rewriting a ruleset
37
to fit in <code>.htaccess</code> context instead
38
of per-server context. Always try to understand what a
39
particular ruleset really does before you use it. This
40
avoids many problems.</div>
43
<div id="quickview"><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#cluster">Webcluster through Homogeneous URL Layout</a></li>
44
<li><img alt="" src="../images/down.gif" /> <a href="#structuredhomedirs">Structured Homedirs</a></li>
45
<li><img alt="" src="../images/down.gif" /> <a href="#filereorg">Filesystem Reorganization</a></li>
46
<li><img alt="" src="../images/down.gif" /> <a href="#redirect404">Redirect Failing URLs To Other Webserver</a></li>
47
<li><img alt="" src="../images/down.gif" /> Archive Access Multiplexer</li>
48
<li><img alt="" src="../images/down.gif" /> <a href="#content">Content Handling</a></li>
49
<li><img alt="" src="../images/down.gif" /> <a href="#access">Access Restriction</a></li>
50
</ul><h3>See also</h3><ul class="seealso"><li><a href="../mod/mod_rewrite.html">Module
51
documentation</a></li><li><a href="rewrite_intro.html">mod_rewrite
52
introduction</a></li><li><a href="rewrite_guide.html">Practical solutions to common
53
problems</a></li><li><a href="rewrite_tech.html">Technical details</a></li></ul></div>
54
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
56
<h2><a name="cluster" id="cluster">Webcluster through Homogeneous URL Layout</a></h2>
64
<p>We want to create a homogeneous and consistent URL
65
layout over all WWW servers on a Intranet webcluster, i.e.
66
all URLs (per definition server local and thus server
67
dependent!) become actually server <em>independent</em>!
68
What we want is to give the WWW namespace a consistent
69
server-independent layout: no URL should have to include
70
any physically correct target server. The cluster itself
71
should drive us automatically to the physical target
78
<p>First, the knowledge of the target servers come from
79
(distributed) external maps which contain information
80
where our users, groups and entities stay. The have the
83
<div class="example"><pre>
89
<p>We put them into files <code>map.xxx-to-host</code>.
90
Second we need to instruct all servers to redirect URLs
93
<div class="example"><pre>
101
<div class="example"><pre>
102
http://physical-host/u/user/anypath
103
http://physical-host/g/group/anypath
104
http://physical-host/e/entity/anypath
107
<p>when the URL is not locally valid to a server. The
108
following ruleset does this for us by the help of the map
109
files (assuming that server0 is a default server which
110
will be used if a user has no entry in the map):</p>
112
<div class="example"><pre>
115
RewriteMap user-to-host txt:/path/to/map.user-to-host
116
RewriteMap group-to-host txt:/path/to/map.group-to-host
117
RewriteMap entity-to-host txt:/path/to/map.entity-to-host
119
RewriteRule ^/u/<strong>([^/]+)</strong>/?(.*) http://<strong>${user-to-host:$1|server0}</strong>/u/$1/$2
120
RewriteRule ^/g/<strong>([^/]+)</strong>/?(.*) http://<strong>${group-to-host:$1|server0}</strong>/g/$1/$2
121
RewriteRule ^/e/<strong>([^/]+)</strong>/?(.*) http://<strong>${entity-to-host:$1|server0}</strong>/e/$1/$2
123
RewriteRule ^/([uge])/([^/]+)/?$ /$1/$2/.www/
124
RewriteRule ^/([uge])/([^/]+)/([^.]+.+) /$1/$2/.www/$3\
129
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
130
<div class="section">
131
<h2><a name="structuredhomedirs" id="structuredhomedirs">Structured Homedirs</a></h2>
136
<dt>Description:</dt>
139
<p>Some sites with thousands of users usually use a
140
structured homedir layout, i.e. each homedir is in a
141
subdirectory which begins for instance with the first
142
character of the username. So, <code>/~foo/anypath</code>
143
is <code>/home/<strong>f</strong>/foo/.www/anypath</code>
144
while <code>/~bar/anypath</code> is
145
<code>/home/<strong>b</strong>/bar/.www/anypath</code>.</p>
151
<p>We use the following ruleset to expand the tilde URLs
152
into exactly the above layout.</p>
154
<div class="example"><pre>
156
RewriteRule ^/~(<strong>([a-z])</strong>[a-z0-9]+)(.*) /home/<strong>$2</strong>/$1/.www$3
161
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
162
<div class="section">
163
<h2><a name="filereorg" id="filereorg">Filesystem Reorganization</a></h2>
168
<dt>Description:</dt>
171
<p>This really is a hardcore example: a killer application
172
which heavily uses per-directory
173
<code>RewriteRules</code> to get a smooth look and feel
174
on the Web while its data structure is never touched or
175
adjusted. Background: <strong><em>net.sw</em></strong> is
176
my archive of freely available Unix software packages,
177
which I started to collect in 1992. It is both my hobby
178
and job to to this, because while I'm studying computer
179
science I have also worked for many years as a system and
180
network administrator in my spare time. Every week I need
181
some sort of software so I created a deep hierarchy of
182
directories where I stored the packages:</p>
184
<div class="example"><pre>
185
drwxrwxr-x 2 netsw users 512 Aug 3 18:39 Audio/
186
drwxrwxr-x 2 netsw users 512 Jul 9 14:37 Benchmark/
187
drwxrwxr-x 12 netsw users 512 Jul 9 00:34 Crypto/
188
drwxrwxr-x 5 netsw users 512 Jul 9 00:41 Database/
189
drwxrwxr-x 4 netsw users 512 Jul 30 19:25 Dicts/
190
drwxrwxr-x 10 netsw users 512 Jul 9 01:54 Graphic/
191
drwxrwxr-x 5 netsw users 512 Jul 9 01:58 Hackers/
192
drwxrwxr-x 8 netsw users 512 Jul 9 03:19 InfoSys/
193
drwxrwxr-x 3 netsw users 512 Jul 9 03:21 Math/
194
drwxrwxr-x 3 netsw users 512 Jul 9 03:24 Misc/
195
drwxrwxr-x 9 netsw users 512 Aug 1 16:33 Network/
196
drwxrwxr-x 2 netsw users 512 Jul 9 05:53 Office/
197
drwxrwxr-x 7 netsw users 512 Jul 9 09:24 SoftEng/
198
drwxrwxr-x 7 netsw users 512 Jul 9 12:17 System/
199
drwxrwxr-x 12 netsw users 512 Aug 3 20:15 Typesetting/
200
drwxrwxr-x 10 netsw users 512 Jul 9 14:08 X11/
203
<p>In July 1996 I decided to make this archive public to
204
the world via a nice Web interface. "Nice" means that I
205
wanted to offer an interface where you can browse
206
directly through the archive hierarchy. And "nice" means
207
that I didn't wanted to change anything inside this
208
hierarchy - not even by putting some CGI scripts at the
209
top of it. Why? Because the above structure should be
210
later accessible via FTP as well, and I didn't want any
211
Web or CGI stuff to be there.</p>
217
<p>The solution has two parts: The first is a set of CGI
218
scripts which create all the pages at all directory
219
levels on-the-fly. I put them under
220
<code>/e/netsw/.www/</code> as follows:</p>
222
<div class="example"><pre>
223
-rw-r--r-- 1 netsw users 1318 Aug 1 18:10 .wwwacl
224
drwxr-xr-x 18 netsw users 512 Aug 5 15:51 DATA/
225
-rw-rw-rw- 1 netsw users 372982 Aug 5 16:35 LOGFILE
226
-rw-r--r-- 1 netsw users 659 Aug 4 09:27 TODO
227
-rw-r--r-- 1 netsw users 5697 Aug 1 18:01 netsw-about.html
228
-rwxr-xr-x 1 netsw users 579 Aug 2 10:33 netsw-access.pl
229
-rwxr-xr-x 1 netsw users 1532 Aug 1 17:35 netsw-changes.cgi
230
-rwxr-xr-x 1 netsw users 2866 Aug 5 14:49 netsw-home.cgi
231
drwxr-xr-x 2 netsw users 512 Jul 8 23:47 netsw-img/
232
-rwxr-xr-x 1 netsw users 24050 Aug 5 15:49 netsw-lsdir.cgi
233
-rwxr-xr-x 1 netsw users 1589 Aug 3 18:43 netsw-search.cgi
234
-rwxr-xr-x 1 netsw users 1885 Aug 1 17:41 netsw-tree.cgi
235
-rw-r--r-- 1 netsw users 234 Jul 30 16:35 netsw-unlimit.lst
238
<p>The <code>DATA/</code> subdirectory holds the above
239
directory structure, i.e. the real
240
<strong><em>net.sw</em></strong> stuff and gets
241
automatically updated via <code>rdist</code> from time to
242
time. The second part of the problem remains: how to link
243
these two structures together into one smooth-looking URL
244
tree? We want to hide the <code>DATA/</code> directory
245
from the user while running the appropriate CGI scripts
246
for the various URLs. Here is the solution: first I put
247
the following into the per-directory configuration file
248
in the <code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code>
249
of the server to rewrite the announced URL
250
<code>/net.sw/</code> to the internal path
251
<code>/e/netsw</code>:</p>
253
<div class="example"><pre>
254
RewriteRule ^net.sw$ net.sw/ [R]
255
RewriteRule ^net.sw/(.*)$ e/netsw/$1
258
<p>The first rule is for requests which miss the trailing
259
slash! The second rule does the real thing. And then
260
comes the killer configuration which stays in the
261
per-directory config file
262
<code>/e/netsw/.www/.wwwacl</code>:</p>
264
<div class="example"><pre>
265
Options ExecCGI FollowSymLinks Includes MultiViews
269
# we are reached via /net.sw/ prefix
272
# first we rewrite the root dir to
273
# the handling cgi script
274
RewriteRule ^$ netsw-home.cgi [L]
275
RewriteRule ^index\.html$ netsw-home.cgi [L]
277
# strip out the subdirs when
278
# the browser requests us from perdir pages
279
RewriteRule ^.+/(netsw-[^/]+/.+)$ $1 [L]
281
# and now break the rewriting for local files
282
RewriteRule ^netsw-home\.cgi.* - [L]
283
RewriteRule ^netsw-changes\.cgi.* - [L]
284
RewriteRule ^netsw-search\.cgi.* - [L]
285
RewriteRule ^netsw-tree\.cgi$ - [L]
286
RewriteRule ^netsw-about\.html$ - [L]
287
RewriteRule ^netsw-img/.*$ - [L]
289
# anything else is a subdir which gets handled
290
# by another cgi script
291
RewriteRule !^netsw-lsdir\.cgi.* - [C]
292
RewriteRule (.*) netsw-lsdir.cgi/$1
295
<p>Some hints for interpretation:</p>
298
<li>Notice the <code>L</code> (last) flag and no
299
substitution field ('<code>-</code>') in the forth part</li>
301
<li>Notice the <code>!</code> (not) character and
302
the <code>C</code> (chain) flag at the first rule
303
in the last part</li>
305
<li>Notice the catch-all pattern in the last rule</li>
310
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
311
<div class="section">
312
<h2><a name="redirect404" id="redirect404">Redirect Failing URLs To Other Webserver</a></h2>
317
<dt>Description:</dt>
320
<p>A typical FAQ about URL rewriting is how to redirect
321
failing requests on webserver A to webserver B. Usually
322
this is done via <code class="directive"><a href="../mod/core.html#errordocument">ErrorDocument</a></code> CGI-scripts in Perl, but
323
there is also a <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code> solution.
324
But notice that this performs more poorly than using an
325
<code class="directive"><a href="../mod/core.html#errordocument">ErrorDocument</a></code>
332
<p>The first solution has the best performance but less
333
flexibility, and is less error safe:</p>
335
<div class="example"><pre>
337
RewriteCond /your/docroot/%{REQUEST_FILENAME} <strong>!-f</strong>
338
RewriteRule ^(.+) http://<strong>webserverB</strong>.dom/$1
341
<p>The problem here is that this will only work for pages
342
inside the <code class="directive"><a href="../mod/core.html#documentroot">DocumentRoot</a></code>. While you can add more
343
Conditions (for instance to also handle homedirs, etc.)
344
there is better variant:</p>
346
<div class="example"><pre>
348
RewriteCond %{REQUEST_URI} <strong>!-U</strong>
349
RewriteRule ^(.+) http://<strong>webserverB</strong>.dom/$1
352
<p>This uses the URL look-ahead feature of <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>.
353
The result is that this will work for all types of URLs
354
and is a safe way. But it does a performance impact on
355
the webserver, because for every request there is one
356
more internal subrequest. So, if your webserver runs on a
357
powerful CPU, use this one. If it is a slow machine, use
358
the first approach or better a <code class="directive"><a href="../mod/core.html#errordocument">ErrorDocument</a></code> CGI-script.</p>
362
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
363
<div class="section">
364
<h2>Archive Access Multiplexer</h2>
369
<dt>Description:</dt>
372
<p>Do you know the great CPAN (Comprehensive Perl Archive
373
Network) under <a href="http://www.perl.com/CPAN">http://www.perl.com/CPAN</a>?
374
This does a redirect to one of several FTP servers around
375
the world which carry a CPAN mirror and is approximately
376
near the location of the requesting client. Actually this
377
can be called an FTP access multiplexing service. While
378
CPAN runs via CGI scripts, how can a similar approach
379
implemented via <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>?</p>
385
<p>First we notice that from version 3.0.0
386
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code> can
387
also use the "<code>ftp:</code>" scheme on redirects.
388
And second, the location approximation can be done by a
389
<code class="directive"><a href="../mod/mod_rewrite.html#rewritemap">RewriteMap</a></code>
390
over the top-level domain of the client.
391
With a tricky chained ruleset we can use this top-level
392
domain as a key to our multiplexing map.</p>
394
<div class="example"><pre>
396
RewriteMap multiplex txt:/path/to/map.cxan
397
RewriteRule ^/CxAN/(.*) %{REMOTE_HOST}::$1 [C]
398
RewriteRule ^.+\.<strong>([a-zA-Z]+)</strong>::(.*)$ ${multiplex:<strong>$1</strong>|ftp.default.dom}$2 [R,L]
401
<div class="example"><pre>
403
## map.cxan -- Multiplexing Map for CxAN
406
de ftp://ftp.cxan.de/CxAN/
407
uk ftp://ftp.cxan.uk/CxAN/
408
com ftp://ftp.cxan.com/CxAN/
415
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
416
<div class="section">
417
<h2><a name="content" id="content">Content Handling</a></h2>
421
<h3>Browser Dependent Content</h3>
426
<dt>Description:</dt>
429
<p>At least for important top-level pages it is sometimes
430
necessary to provide the optimum of browser dependent
431
content, i.e. one has to provide a maximum version for the
432
latest Netscape variants, a minimum version for the Lynx
433
browsers and a average feature version for all others.</p>
439
<p>We cannot use content negotiation because the browsers do
440
not provide their type in that form. Instead we have to
441
act on the HTTP header "User-Agent". The following condig
442
does the following: If the HTTP header "User-Agent"
443
begins with "Mozilla/3", the page <code>foo.html</code>
444
is rewritten to <code>foo.NS.html</code> and and the
445
rewriting stops. If the browser is "Lynx" or "Mozilla" of
446
version 1 or 2 the URL becomes <code>foo.20.html</code>.
447
All other browsers receive page <code>foo.32.html</code>.
448
This is done by the following ruleset:</p>
450
<div class="example"><pre>
451
RewriteCond %{HTTP_USER_AGENT} ^<strong>Mozilla/3</strong>.*
452
RewriteRule ^foo\.html$ foo.<strong>NS</strong>.html [<strong>L</strong>]
454
RewriteCond %{HTTP_USER_AGENT} ^<strong>Lynx/</strong>.* [OR]
455
RewriteCond %{HTTP_USER_AGENT} ^<strong>Mozilla/[12]</strong>.*
456
RewriteRule ^foo\.html$ foo.<strong>20</strong>.html [<strong>L</strong>]
458
RewriteRule ^foo\.html$ foo.<strong>32</strong>.html [<strong>L</strong>]
465
<h3>Dynamic Mirror</h3>
470
<dt>Description:</dt>
473
<p>Assume there are nice webpages on remote hosts we want
474
to bring into our namespace. For FTP servers we would use
475
the <code>mirror</code> program which actually maintains an
476
explicit up-to-date copy of the remote data on the local
477
machine. For a webserver we could use the program
478
<code>webcopy</code> which acts similar via HTTP. But both
479
techniques have one major drawback: The local copy is
480
always just as up-to-date as often we run the program. It
481
would be much better if the mirror is not a static one we
482
have to establish explicitly. Instead we want a dynamic
483
mirror with data which gets updated automatically when
484
there is need (updated data on the remote host).</p>
490
<p>To provide this feature we map the remote webpage or even
491
the complete remote webarea to our namespace by the use
492
of the <dfn>Proxy Throughput</dfn> feature
493
(flag <code>[P]</code>):</p>
495
<div class="example"><pre>
498
RewriteRule ^<strong>hotsheet/</strong>(.*)$ <strong>http://www.tstimpreso.com/hotsheet/</strong>$1 [<strong>P</strong>]
501
<div class="example"><pre>
504
RewriteRule ^<strong>usa-news\.html</strong>$ <strong>http://www.quux-corp.com/news/index.html</strong> [<strong>P</strong>]
511
<h3>Reverse Dynamic Mirror</h3>
516
<dt>Description:</dt>
523
<div class="example"><pre>
525
RewriteCond /mirror/of/remotesite/$1 -U
526
RewriteRule ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1
533
<h3>Retrieve Missing Data from Intranet</h3>
538
<dt>Description:</dt>
541
<p>This is a tricky way of virtually running a corporate
542
(external) Internet webserver
543
(<code>www.quux-corp.dom</code>), while actually keeping
544
and maintaining its data on a (internal) Intranet webserver
545
(<code>www2.quux-corp.dom</code>) which is protected by a
546
firewall. The trick is that on the external webserver we
547
retrieve the requested data on-the-fly from the internal
554
<p>First, we have to make sure that our firewall still
555
protects the internal webserver and that only the
556
external webserver is allowed to retrieve data from it.
557
For a packet-filtering firewall we could for instance
558
configure a firewall ruleset like the following:</p>
560
<div class="example"><pre>
561
<strong>ALLOW</strong> Host www.quux-corp.dom Port >1024 --> Host www2.quux-corp.dom Port <strong>80</strong>
562
<strong>DENY</strong> Host * Port * --> Host www2.quux-corp.dom Port <strong>80</strong>
565
<p>Just adjust it to your actual configuration syntax.
566
Now we can establish the <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>
567
rules which request the missing data in the background
568
through the proxy throughput feature:</p>
570
<div class="example"><pre>
571
RewriteRule ^/~([^/]+)/?(.*) /home/$1/.www/$2
572
RewriteCond %{REQUEST_FILENAME} <strong>!-f</strong>
573
RewriteCond %{REQUEST_FILENAME} <strong>!-d</strong>
574
RewriteRule ^/home/([^/]+)/.www/?(.*) http://<strong>www2</strong>.quux-corp.dom/~$1/pub/$2 [<strong>P</strong>]
581
<h3>Load Balancing</h3>
586
<dt>Description:</dt>
589
<p>Suppose we want to load balance the traffic to
590
<code>www.foo.com</code> over <code>www[0-5].foo.com</code>
591
(a total of 6 servers). How can this be done?</p>
597
<p>There are a lot of possible solutions for this problem.
598
We will discuss first a commonly known DNS-based variant
599
and then the special one with <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>:</p>
603
<strong>DNS Round-Robin</strong>
605
<p>The simplest method for load-balancing is to use
606
the DNS round-robin feature of <code>BIND</code>.
607
Here you just configure <code>www[0-9].foo.com</code>
608
as usual in your DNS with A(address) records, e.g.</p>
610
<div class="example"><pre>
619
<p>Then you additionally add the following entry:</p>
621
<div class="example"><pre>
622
www IN CNAME www0.foo.com.
623
IN CNAME www1.foo.com.
624
IN CNAME www2.foo.com.
625
IN CNAME www3.foo.com.
626
IN CNAME www4.foo.com.
627
IN CNAME www5.foo.com.
628
IN CNAME www6.foo.com.
631
<p>Notice that this seems wrong, but is actually an
632
intended feature of <code>BIND</code> and can be used
633
in this way. However, now when <code>www.foo.com</code> gets
634
resolved, <code>BIND</code> gives out <code>www0-www6</code>
635
- but in a slightly permutated/rotated order every time.
636
This way the clients are spread over the various
637
servers. But notice that this not a perfect load
638
balancing scheme, because DNS resolve information
639
gets cached by the other nameservers on the net, so
640
once a client has resolved <code>www.foo.com</code>
641
to a particular <code>wwwN.foo.com</code>, all
642
subsequent requests also go to this particular name
643
<code>wwwN.foo.com</code>. But the final result is
644
ok, because the total sum of the requests are really
645
spread over the various webservers.</p>
649
<strong>DNS Load-Balancing</strong>
651
<p>A sophisticated DNS-based method for
652
load-balancing is to use the program
653
<code>lbnamed</code> which can be found at <a href="http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html">
654
http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html</a>.
655
It is a Perl 5 program in conjunction with auxilliary
656
tools which provides a real load-balancing for
661
<strong>Proxy Throughput Round-Robin</strong>
663
<p>In this variant we use <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>
664
and its proxy throughput feature. First we dedicate
665
<code>www0.foo.com</code> to be actually
666
<code>www.foo.com</code> by using a single</p>
668
<div class="example"><pre>
669
www IN CNAME www0.foo.com.
672
<p>entry in the DNS. Then we convert
673
<code>www0.foo.com</code> to a proxy-only server,
674
i.e. we configure this machine so all arriving URLs
675
are just pushed through the internal proxy to one of
676
the 5 other servers (<code>www1-www5</code>). To
677
accomplish this we first establish a ruleset which
678
contacts a load balancing script <code>lb.pl</code>
681
<div class="example"><pre>
683
RewriteMap lb prg:/path/to/lb.pl
684
RewriteRule ^/(.+)$ ${lb:$1} [P,L]
687
<p>Then we write <code>lb.pl</code>:</p>
689
<div class="example"><pre>
692
## lb.pl -- load balancing script
697
$name = "www"; # the hostname base
698
$first = 1; # the first server (not 0 here, because 0 is myself)
699
$last = 5; # the last server in the round-robin
700
$domain = "foo.dom"; # the domainname
703
while (<STDIN>) {
704
$cnt = (($cnt+1) % ($last+1-$first));
705
$server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
706
print "http://$server/$_";
712
<div class="note">A last notice: Why is this useful? Seems like
713
<code>www0.foo.com</code> still is overloaded? The
714
answer is yes, it is overloaded, but with plain proxy
715
throughput requests, only! All SSI, CGI, ePerl, etc.
716
processing is completely done on the other machines.
717
This is the essential point.</div>
721
<strong>Hardware/TCP Round-Robin</strong>
723
<p>There is a hardware solution available, too. Cisco
724
has a beast called LocalDirector which does a load
725
balancing at the TCP/IP level. Actually this is some
726
sort of a circuit level gateway in front of a
727
webcluster. If you have enough money and really need
728
a solution with high performance, use this one.</p>
736
<h3>New MIME-type, New Service</h3>
741
<dt>Description:</dt>
744
<p>On the net there are a lot of nifty CGI programs. But
745
their usage is usually boring, so a lot of webmaster
746
don't use them. Even Apache's Action handler feature for
747
MIME-types is only appropriate when the CGI programs
748
don't need special URLs (actually <code>PATH_INFO</code>
749
and <code>QUERY_STRINGS</code>) as their input. First,
750
let us configure a new file type with extension
751
<code>.scgi</code> (for secure CGI) which will be processed
752
by the popular <code>cgiwrap</code> program. The problem
753
here is that for instance we use a Homogeneous URL Layout
754
(see above) a file inside the user homedirs has the URL
755
<code>/u/user/foo/bar.scgi</code>. But
756
<code>cgiwrap</code> needs the URL in the form
757
<code>/~user/foo/bar.scgi/</code>. The following rule
758
solves the problem:</p>
760
<div class="example"><pre>
761
RewriteRule ^/[uge]/<strong>([^/]+)</strong>/\.www/(.+)\.scgi(.*) ...
762
... /internal/cgi/user/cgiwrap/~<strong>$1</strong>/$2.scgi$3 [NS,<strong>T=application/x-http-cgi</strong>]
765
<p>Or assume we have some more nifty programs:
766
<code>wwwlog</code> (which displays the
767
<code>access.log</code> for a URL subtree and
768
<code>wwwidx</code> (which runs Glimpse on a URL
769
subtree). We have to provide the URL area to these
770
programs so they know on which area they have to act on.
771
But usually this ugly, because they are all the times
772
still requested from that areas, i.e. typically we would
773
run the <code>swwidx</code> program from within
774
<code>/u/user/foo/</code> via hyperlink to</p>
776
<div class="example"><pre>
777
/internal/cgi/user/swwidx?i=/u/user/foo/
780
<p>which is ugly. Because we have to hard-code
781
<strong>both</strong> the location of the area
782
<strong>and</strong> the location of the CGI inside the
783
hyperlink. When we have to reorganize the area, we spend a
784
lot of time changing the various hyperlinks.</p>
790
<p>The solution here is to provide a special new URL format
791
which automatically leads to the proper CGI invocation.
792
We configure the following:</p>
794
<div class="example"><pre>
795
RewriteRule ^/([uge])/([^/]+)(/?.*)/\* /internal/cgi/user/wwwidx?i=/$1/$2$3/
796
RewriteRule ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3
799
<p>Now the hyperlink to search at
800
<code>/u/user/foo/</code> reads only</p>
802
<div class="example"><pre>
806
<p>which internally gets automatically transformed to</p>
808
<div class="example"><pre>
809
/internal/cgi/user/wwwidx?i=/u/user/foo/
812
<p>The same approach leads to an invocation for the
813
access log CGI program when the hyperlink
814
<code>:log</code> gets used.</p>
820
<h3>On-the-fly Content-Regeneration</h3>
825
<dt>Description:</dt>
828
<p>Here comes a really esoteric feature: Dynamically
829
generated but statically served pages, i.e. pages should be
830
delivered as pure static pages (read from the filesystem
831
and just passed through), but they have to be generated
832
dynamically by the webserver if missing. This way you can
833
have CGI-generated pages which are statically served unless
834
one (or a cronjob) removes the static contents. Then the
835
contents gets refreshed.</p>
841
This is done via the following ruleset:
843
<div class="example"><pre>
844
RewriteCond %{REQUEST_FILENAME} <strong>!-s</strong>
845
RewriteRule ^page\.<strong>html</strong>$ page.<strong>cgi</strong> [T=application/x-httpd-cgi,L]
848
<p>Here a request to <code>page.html</code> leads to a
849
internal run of a corresponding <code>page.cgi</code> if
850
<code>page.html</code> is still missing or has filesize
851
null. The trick here is that <code>page.cgi</code> is a
852
usual CGI script which (additionally to its <code>STDOUT</code>)
853
writes its output to the file <code>page.html</code>.
854
Once it was run, the server sends out the data of
855
<code>page.html</code>. When the webmaster wants to force
856
a refresh the contents, he just removes
857
<code>page.html</code> (usually done by a cronjob).</p>
863
<h3>Document With Autorefresh</h3>
868
<dt>Description:</dt>
871
<p>Wouldn't it be nice while creating a complex webpage if
872
the webbrowser would automatically refresh the page every
873
time we write a new version from within our editor?
880
<p>No! We just combine the MIME multipart feature, the
881
webserver NPH feature and the URL manipulation power of
882
<code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>. First, we establish a new
883
URL feature: Adding just <code>:refresh</code> to any
884
URL causes this to be refreshed every time it gets
885
updated on the filesystem.</p>
887
<div class="example"><pre>
888
RewriteRule ^(/[uge]/[^/]+/?.*):refresh /internal/cgi/apache/nph-refresh?f=$1
891
<p>Now when we reference the URL</p>
893
<div class="example"><pre>
894
/u/foo/bar/page.html:refresh
897
<p>this leads to the internal invocation of the URL</p>
899
<div class="example"><pre>
900
/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
903
<p>The only missing part is the NPH-CGI script. Although
904
one would usually say "left as an exercise to the reader"
905
;-) I will provide this, too.</p>
907
<div class="example"><pre>
910
## nph-refresh -- NPH/CGI script for auto refreshing pages
911
## Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
915
# split the QUERY_STRING variable
916
@pairs = split(/&/, $ENV{'QUERY_STRING'});
917
foreach $pair (@pairs) {
918
($name, $value) = split(/=/, $pair);
919
$name =~ tr/A-Z/a-z/;
920
$name = 'QS_' . $name;
921
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
922
eval "\$$name = \"$value\"";
924
$QS_s = 1 if ($QS_s eq '');
925
$QS_n = 3600 if ($QS_n eq '');
927
print "HTTP/1.0 200 OK\n";
928
print "Content-type: text/html\n\n";
929
print "&lt;b&gt;ERROR&lt;/b&gt;: No file given\n";
933
print "HTTP/1.0 200 OK\n";
934
print "Content-type: text/html\n\n";
935
print "&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n";
939
sub print_http_headers_multipart_begin {
940
print "HTTP/1.0 200 OK\n";
941
$bound = "ThisRandomString12345";
942
print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
943
&print_http_headers_multipart_next;
946
sub print_http_headers_multipart_next {
947
print "\n--$bound\n";
950
sub print_http_headers_multipart_end {
951
print "\n--$bound--\n";
956
$len = length($buffer);
957
print "Content-type: text/html\n";
958
print "Content-length: $len\n\n";
964
local(*FP, $size, $buffer, $bytes);
965
($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
966
$size = sprintf("%d", $size);
967
open(FP, "&lt;$file");
968
$bytes = sysread(FP, $buffer, $size);
973
$buffer = &readfile($QS_f);
974
&print_http_headers_multipart_begin;
975
&displayhtml($buffer);
978
local($file) = $_[0];
981
($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
985
$mtimeL = &mystat($QS_f);
987
for ($n = 0; $n &lt; $QS_n; $n++) {
989
$mtime = &mystat($QS_f);
990
if ($mtime ne $mtimeL) {
993
$buffer = &readfile($QS_f);
994
&print_http_headers_multipart_next;
995
&displayhtml($buffer);
997
$mtimeL = &mystat($QS_f);
1004
&print_http_headers_multipart_end;
1015
<h3>Mass Virtual Hosting</h3>
1020
<dt>Description:</dt>
1023
<p>The <code class="directive"><a href="../mod/core.html#virtualhost"><VirtualHost></a></code> feature of Apache is nice
1024
and works great when you just have a few dozens
1025
virtual hosts. But when you are an ISP and have hundreds of
1026
virtual hosts to provide this feature is not the best
1033
<p>To provide this feature we map the remote webpage or even
1034
the complete remote webarea to our namespace by the use
1035
of the <dfn>Proxy Throughput</dfn> feature (flag <code>[P]</code>):</p>
1037
<div class="example"><pre>
1041
www.vhost1.dom:80 /path/to/docroot/vhost1
1042
www.vhost2.dom:80 /path/to/docroot/vhost2
1044
www.vhostN.dom:80 /path/to/docroot/vhostN
1047
<div class="example"><pre>
1052
# use the canonical hostname on redirects, etc.
1056
# add the virtual host in front of the CLF-format
1057
CustomLog /path/to/access_log "%{VHOST}e %h %l %u %t \"%r\" %>s %b"
1060
# enable the rewriting engine in the main server
1063
# define two maps: one for fixing the URL and one which defines
1064
# the available virtual hosts with their corresponding
1066
RewriteMap lowercase int:tolower
1067
RewriteMap vhost txt:/path/to/vhost.map
1069
# Now do the actual virtual host mapping
1070
# via a huge and complicated single rule:
1072
# 1. make sure we don't map for common locations
1073
RewriteCond %{REQUEST_URI} !^/commonurl1/.*
1074
RewriteCond %{REQUEST_URI} !^/commonurl2/.*
1076
RewriteCond %{REQUEST_URI} !^/commonurlN/.*
1078
# 2. make sure we have a Host header, because
1079
# currently our approach only supports
1080
# virtual hosting through this header
1081
RewriteCond %{HTTP_HOST} !^$
1083
# 3. lowercase the hostname
1084
RewriteCond ${lowercase:%{HTTP_HOST}|NONE} ^(.+)$
1086
# 4. lookup this hostname in vhost.map and
1087
# remember it only when it is a path
1088
# (and not "NONE" from above)
1089
RewriteCond ${vhost:%1} ^(/.*)$
1091
# 5. finally we can map the URL to its docroot location
1092
# and remember the virtual host for logging puposes
1093
RewriteRule ^/(.*)$ %1/$1 [E=VHOST:${lowercase:%{HTTP_HOST}}]
1101
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
1102
<div class="section">
1103
<h2><a name="access" id="access">Access Restriction</a></h2>
1112
<dt>Description:</dt>
1115
<p>How can we forbid a list of externally configured hosts
1116
from using our server?</p>
1122
<p>For Apache >= 1.3b6:</p>
1124
<div class="example"><pre>
1126
RewriteMap hosts-deny txt:/path/to/hosts.deny
1127
RewriteCond ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
1128
RewriteCond ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
1129
RewriteRule ^/.* - [F]
1132
<p>For Apache <= 1.3b6:</p>
1134
<div class="example"><pre>
1136
RewriteMap hosts-deny txt:/path/to/hosts.deny
1137
RewriteRule ^/(.*)$ ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}/$1
1138
RewriteRule !^NOT-FOUND/.* - [F]
1139
RewriteRule ^NOT-FOUND/(.*)$ ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}/$1
1140
RewriteRule !^NOT-FOUND/.* - [F]
1141
RewriteRule ^NOT-FOUND/(.*)$ /$1
1144
<div class="example"><pre>
1148
## ATTENTION! This is a map, not a list, even when we treat it as such.
1149
## mod_rewrite parses it for key/value pairs, so at least a
1150
## dummy value "-" must be present for each entry.
1167
<dt>Description:</dt>
1170
<p>How can we forbid a certain host or even a user of a
1171
special host from using the Apache proxy?</p>
1177
<p>We first have to make sure <code class="module"><a href="../mod/mod_rewrite.html">mod_rewrite</a></code>
1178
is below(!) <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code> in the Configuration
1179
file when compiling the Apache webserver. This way it gets
1180
called <em>before</em> <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code>. Then we
1181
configure the following for a host-dependent deny...</p>
1183
<div class="example"><pre>
1184
RewriteCond %{REMOTE_HOST} <strong>^badhost\.mydomain\.com$</strong>
1185
RewriteRule !^http://[^/.]\.mydomain.com.* - [F]
1188
<p>...and this one for a user@host-dependent deny:</p>
1190
<div class="example"><pre>
1191
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>^badguy@badhost\.mydomain\.com$</strong>
1192
RewriteRule !^http://[^/.]\.mydomain.com.* - [F]
1199
<h3>Special Authentication Variant</h3>
1204
<dt>Description:</dt>
1207
<p>Sometimes a very special authentication is needed, for
1208
instance a authentication which checks for a set of
1209
explicitly configured users. Only these should receive
1210
access and without explicit prompting (which would occur
1211
when using the Basic Auth via <code class="module"><a href="../mod/mod_auth.html">mod_auth</a></code>).</p>
1217
<p>We use a list of rewrite conditions to exclude all except
1220
<div class="example"><pre>
1221
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend1@client1.quux-corp\.com$</strong>
1222
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend2</strong>@client2.quux-corp\.com$
1223
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend3</strong>@client3.quux-corp\.com$
1224
RewriteRule ^/~quux/only-for-friends/ - [F]
1231
<h3>Referer-based Deflector</h3>
1236
<dt>Description:</dt>
1239
<p>How can we program a flexible URL Deflector which acts
1240
on the "Referer" HTTP header and can be configured with as
1241
many referring pages as we like?</p>
1247
<p>Use the following really tricky ruleset...</p>
1249
<div class="example"><pre>
1250
RewriteMap deflector txt:/path/to/deflector.map
1252
RewriteCond %{HTTP_REFERER} !=""
1253
RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
1254
RewriteRule ^.* %{HTTP_REFERER} [R,L]
1256
RewriteCond %{HTTP_REFERER} !=""
1257
RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
1258
RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]
1261
<p>... in conjunction with a corresponding rewrite
1264
<div class="example"><pre>
1269
http://www.badguys.com/bad/index.html -
1270
http://www.badguys.com/bad/index2.html -
1271
http://www.badguys.com/bad/index3.html http://somewhere.com/
1274
<p>This automatically redirects the request back to the
1275
referring page (when "<code>-</code>" is used as the value
1276
in the map) or to a specific URL (when an URL is specified
1277
in the map as the second argument).</p>
1284
<div class="bottomlang">
1285
<p><span>Available Languages: </span><a href="../en/rewrite/rewrite_guide_advanced.html" title="English"> en </a></p>
1286
</div><div id="footer">
1287
<p class="apache">Copyright 2006 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>
1288
<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/directives.html">Directives</a> | <a href="../faq/">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div>
b'\\ No newline at end of file'