Show Contents Previous Page Next Page
Chapter 8 - Customizing the Apache Configuration Process Configuring Apache with Perl In this section... Introduction Show Contents Go to Top Previous Page Next Page We've just seen how you can configure Perl modules using the Apache configuration
mechanism. Now we turn it around to show you how to configure Apache from
within Perl. Instead of configuring Apache by hand (editing a set of configuration
files), the Perl API allows you to write a set of Perl statements to dynamically
configure Apache at runtime. This gives you limitless flexibility. For example,
you can create complex configurations involving hundreds of virtual hosts
without manually typing hundreds of <VirtualHost> sections
into httpd.conf. Or you can write a master configuration file that
will work without modification on any machine in a "server farm." You could
even look up configuration information at runtime from a relational database.
The key to Perl-based server configuration is the <Perl>
directive. Unlike the other directives defined by mod_perl , this
directive is paired to a corresponding </Perl> directive, forming
a Perl section. When Apache hits a Perl section during startup time, it passes everything
within the section to mod_perl . mod_perl , in turn,
compiles the contents of the section by evaluating it inside the Apache::ReadConfig
package. After compilation is finished, mod_perl walks the Apache::ReadConfig
symbol table looking for global variables with the same names as Apache's
configuration directives. The values of those globals are then fed into Apache's
normal configuration mechanism as if they'd been typed directly into the configuration
file. The upshot of all this is that instead of setting the account under
which the server runs with the User directive:
User www
you can write this: <Perl>
$User = 'www';
</Perl>
This doesn't look like much of a win until you consider that you can set
this global using any arbitrary Perl expression, for example:
<Perl>
my $hostname = `hostname`;
$User = 'www' if $hostname =~ /^papa-bear/;
$User = 'httpd' if $hostname =~ /^momma-bear/;
$User = 'nobody' if $hostname =~ /^goldilocks/;
</Perl>
The Perl global that you set must match the spelling of the corresponding
Apache directive. Globals that do not match known Apache directives are silently
ignored. Capitalization is not currently significant. In addition to single-valued directives such as User, Group,
and ServerRoot, you can use <Perl> sections to set
multivalued directives such as DirectoryIndex and AddType.
You can also configure multipart sections such as <Directory>
and <VirtualHost>. Depending on the directive, the Perl global
you need to set may be a scalar, an array, or a hash. To figure out what type
of Perl variable to use, follow these rules: - Directive takes no arguments
There are few examples of configuration directives that take no arguments.
The only one that occurs in the standard Apache modules is CacheNegotiatedDocs,
which is part of mod_ negotiation. To create a nonargument directive,
set the corresponding scalar variable to the empty string '' :
$CacheNegotiatedDocs = '';
- Directive takes one argument
This is probably the most common case. Set the corresponding global to
the value of your choice.
$Port = 8080;
- Directive takes multiple arguments
These include directives such as DirectoryIndex and AddType.
Create a global array with the name of the directive and set it to the list
of desired arguments.
@DirectoryIndex = map { "index.$_" } qw(html htm shtml cgi);
An alternative to this is to create a scalar variable containing the usual
value of the directive as a string, for example:
$DirectoryIndex = "index.html index.htm index.shtml index.cgi";
- Directive is repeated multiple times
If a directive is repeated multiple times with different arguments each
time, you can represent it as an array of arrays. This example using the
AddIcon directive shows how:
@AddIcon = (
[ '/icons/compressed.gif' => qw(.Z .z .gz .tgz .zip) ],
[ '/icons/layout.gif' => qw(.html .shtml .htm .pdf) ],
);
- Directive is a block section with begin and end tags
Configuration sections like <VirtualHost> and <Directory>
are mapped onto Perl hashes. Use the directive's argument (the hostname,
directory, or URI) as the hash key, and make the value stored at this key
an anonymous hash containing the desired directive/value pairs. This is
easier to see than to describe. Consider the following virtual host section:
<VirtualHost 192.168.2.5:80>
ServerName www.fishfries.org
DocumentRoot /home/httpd/fishfries/htdocs
ErrorLog /home/httpd/fishfries/logs/error.log
TransferLog /home/httpd/fishfries/logs/access.log
ServerAdmin webmaster@fishfries.org
</Virtual>
You can represent this in a <Perl> section by the following
code:
$VirtualHost{'192.168.2.5:80'} = {
ServerName => 'www.fishfries.org',
DocumentRoot => '/home/httpd/fishfries/htdocs',
ErrorLog => '/home/httpd/fishfries/logs/error.log',
TransferLog => '/home/httpd/fishfries/logs/access.log',
ServerAdmin => 'webmaster@fishfries.org',
};
There is no special Perl variable which maps to the <IfModule>
directive container; however, the Apache module method will
provide you with this functionality.
if(Apache->module("mod_ssl.c")) {
push @Include, "ssl.conf";
}
The Apache define() method can be used to implement an
<IfDefine> container, as follows:
if(Apache->define("MOD_SSL")) {
push @Include, "ssl.conf";
}
Certain configuration blocks may require directives to be in a particular
order. As you probably know, Perl does not maintain hash values in any predictable
order. Should you need to preserve order with hashes inside <Perl>
sections, simply install Gurusamy Sarathy's Tie::IxHash module from
CPAN. Once installed, mod_perl will tie %VirtualHost ,
%Directory , %Location , and %Files hashes
to this class, preserving their order when the Apache configuration is generated.
- Directive is a block section with multiple same-value keys
The Apache named virtual host mechanism provides a way to configure virtual
hosts using the same IP address.
NameVirtualHost 192.168.2.5
<VirtualHost 192.168.2.5>
ServerName one.fish.net
ServerAdmin webmaster@one.fish.net
</VirtualHost>
<VirtualHost 192.168.2.5>
ServerName red.fish.net
ServerAdmin webmaster@red.fish.net
</VirtualHost>
In this case, the %VirtualHost syntax from the previous section
would not work, since assigning a hash reference for the given IP address
will overwrite the original entry. The solution is to use an array reference
whose values are hash references, one for each virtual host entry. Example:
$VirtualHost{'192.168.2.5'} = [
{
ServerName => 'one.fish.net',
...
ServerAdmin => 'webmaster@one.fish.net',
},
{
ServerName => 'red.fish.net',
...
ServerAdmin => 'webmaster@red.fish.net',
},
];
- Directive is a nested block
Nested block sections are mapped onto anonymous hashes, much like main
sections. For example, to put two <Directory> sections inside
the virtual host of the previous example, you can use this code:
<Perl>
my $root = '/home/httpd/fishfries';
$VirtualHost{'192.168.2.5:80'} = {
ServerName => 'www.fishfries.org',
DocumentRoot => "$root/htdocs",
ErrorLog => "$root/logs/error.log",
TransferLog => "$root/logs/access.log",
ServerAdmin => 'webmaster@fishfries.org',
Directory => {
"$root/htdocs" => {
Options => 'Indexes FollowSymlinks',
AllowOverride => 'Options Indexes Limit FileInfo',
Order => 'deny,allow',
Deny => 'from all',
Allow => 'from fishfries.org',
},
"$root/cgi-bin" => {
AllowOverride => 'None',
Options => 'ExecCGI',
SetHandler => 'cgi-script',
},
},
};
</Perl>
Notice that all the usual Perlisms, such as interpolation of the $root
variable into the double-quoted strings, still work here. Another thing to
see in this example is that in this case we've chosen to write the multivalued
Options directive as a single string:
Options => 'Indexes FollowSymlinks',
The alternative would be to use an anonymous array for the directive's arguments,
as in:
Options => ['Indexes','FollowSymlinks'],
Both methods work. The only gotcha is that you must always be sure of what
is an argument list and what isn't. In the Options directive, "Indexes"
and "FollowSymlinks" are distinct arguments and can be represented as an anonymous
array. In the Order directive, the string deny,allow
is a single argument, and representing it as the array ['deny','allow']
will not work, even though it looks like it should (use the string
deny,allow instead). <Perl> sections are available if you built and installed
mod_perl with the PERL_SECTIONS configuration variable
set (Appendix B, Building and Installing mod_perl).
They are evaluated in the order in which they appear in httpd.conf,
srm.conf, and access.conf. This allows you to use later
<Perl> sections to override values declared in earlier parts
of the configuration files. Show Contents Go to Top Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |