Show Contents Previous Page Next Page
Chapter 8 - Customizing the Apache Configuration Process / Configuring Apache with Perl A Real-Life Example For a complete example of an Apache configuration constructed with <Perl>
sections, we'll look at Doug's setup. As a freelance contractor, Doug must
often configure his development server in a brand-new environment. Rather
than creating a customized server configuration file each time, Doug uses
a generic configuration that can be brought up anywhere, simply by running:
% httpd -f $HOME/httpd.conf
This one step automatically creates the server and document roots if they
don't exist, as well as the log and configuration directories. It also detects
the user that it is being run as, and configures the User and Group
directives to match. Example 8-5 shows a slightly simplified version
of Doug's httpd.conf. It contains only two hard-coded Apache directives:
# file: httpd.conf
PerlPassEnv HOME
Port 9008
There's a PerlPassEnv directive with the value of HOME ,
required in order to make the value of this environment variable visible to
the code contained within the <Perl> section, and there's a
Port directive set to Doug's favorite port number. The rest of the configuration file is written entirely in Perl:
<Perl>
#!perl
$ServerRoot = "$ENV{HOME}/www";
The <Perl> section begins by choosing a path for the server
root. Doug likes to have his test environment set up under his home directory
in ~/www, so the variable $ServerRoot is set to $ENV{HOME}/www .
The server root will now be correctly configured regardless of whether users'
directories are stored under /home, /users, or /var/users.
unless (-d "$ServerRoot/logs") {
for my $dir ("", qw(logs conf htdocs perl)) {
mkdir "$ServerRoot/$dir", 0755;
}
require File::Copy;
File::Copy::cp($0, "$ServerRoot/conf");
}
Next, the code detects whether the server root has been properly initialized
and, if not, creates the requisite directories and subdirectories. It looks
to see whether $ServerRoot/logs exists and is a directory. If
not, the code proceeds to create the directories, calling mkdir()
repeatedly to create first the server root and subsequently logs,
conf, htdocs, and perl subdirectories beneath it.
The code then copies the generic httpd.conf file that is currently
running into the newly created conf subdirectory, using the File::Copy
module's cp() routine. Somewhat magically, mod_perl
arranges for the Perl global variable $0 to hold the path of
the .conf file that is currently being processed.
if(-e "$ServerRoot/startup.pl") {
$PerlRequire = "startup.pl";
}
Next, the code checks whether there is a startup.pl present in
the configuration directory. If this is the first time the server is being
run, the file won't be present, but there may well be one there later. If
the file exists, the code sets the $PerlRequire global to load
it.
$User = getpwuid($>) || $>;
$Group = getgrgid($)) || $);
$ServerAdmin = $User;
The code sets the User, Group, and ServerAdmin
directives next. The user and group are taken from the Perl magic variables
$> and $) , corresponding to the user and group
IDs of the person who launched the server. Since this is the default when
Apache is run from a nonroot shell, this has no effect now but will be of
use if the server is run as root at a later date. Likewise, $ServerAdmin
is set to the name of the current user.
$ServerName = `hostname`;
$DocumentRoot = "$ServerRoot/htdocs";
my $types = "$ServerRoot/conf/mime.types";
$TypesConfig = -e $types ? $types : "/dev/null";
The server name is set to the current host's name by setting the $ServerName
global, and the document root is set to $ServerRoot/htdocs. We look
to see whether the configuration file mime.types is present and,
if so, use it to set $TypesConfig to this value. Otherwise, we
use /dev/null.
push @Alias,
["/perl" => "$ServerRoot/perl"],
["/icons" => "$ServerRoot/icons"];
Next, the <Perl> section declares some directory aliases.
The URI /perl is aliased to $ServerRoot/perl, and /icons
is aliased to $ServerRoot/icons. Notice how the @Alias
global is set to an array of arrays in order to express that it contains multiple
Alias directives.
my $servers = 3;
for my $s (qw(MinSpareServers MaxSpareServers StartServers MaxClients)) {
$$s = $servers;
}
Following this, the code sets the various parameters controlling Apache's
preforking. The server doesn't need to handle much load, since it's just Doug's
development server, so MaxSpareServers and friends are all set
to a low value of three. We use "symbolic" or "soft" references here to set
the globals indirectly. We loop through a set of strings containing the names
of the globals we wish to set, and assign values to them as if they were scalar
references rather than plain strings. Perl automatically updates the symbol
table for us, avoiding the much more convoluted code that would be required
to create the global using globs or by accessing the symbol table directly.
Note that this technique will be blocked if strict reference checking is turned
on with use strict 'refs' .
for my $l (qw(LockFile ErrorLog TransferLog PidFile ScoreBoardFile)) {
$$l = "logs/$l";
#clean out the logs
local *FH;
open FH, ">$ServerRoot/$$l";
close FH;
}
We use a similar trick to configure the LockFile, ErrorLog,
TransferLog, and other log file-related directives. A few additional
lines of code truncate the various log files to zero length if they already
exist. Doug likes to start with a clean slate every time he reconfigures and
restarts a server.
my @mod_perl_cfg = qw{
SetHandler perl-script
Options +ExecCGI
};
$Location{"/perl-status"} = {
@mod_perl_cfg,
PerlHandler => "Apache::Status",
};
$Location{"/perl"} = {
@mod_perl_cfg,
PerlHandler => "Apache::Registry",
};
The remainder of the configuration file sets up some directories for running
and debugging Perl API modules. We create a lexical variable named @mod_perl_cfg
that contains some common options, and then use it to configure the /perl-status
and /perl <Location> sections. The /perl-status
URI is set up so that it runs Apache::Status when retrieved, and
/perl is put under the control of Apache::Registry for use
with registry scripts.
use Apache::PerlSections ();
Apache::PerlSections->store("$ServerRoot/ServerConfig.pm");
The very last thing that the <Perl> section does is to write
out the current configuration into the file $ServerRoot/ServerConfig.pm.
This snapshots the current configuration in a form that Doug can review and
edit, if necessary. Just the configuration variables set within the <Perl>
section are snapshot. The PerlPass-Env and Port directives,
which are outside the section, are not captured and will have to be added
manually. This technique makes possible the following interesting trick:
% httpd -C "PerlModule ServerConfig"
The -C switch tells httpd to process the directive PerlModule,
which in turn loads the module file ServerConfig.pm. Provided that
Perl's PERL5LIB environment variable is set up in such a way
that Perl will be able to find the module, this has the effect of reloading
the previously saved configuration and setting Apache to exactly the same
state it had before.
Example 8-5. Doug's Generic httpd.conf
# file: httpd.conf
PerlPassEnv HOME
Port 9008
<Perl>
#!perl
$ServerRoot = "$ENV{HOME}/www";
unless (-d "$ServerRoot/logs") {
for my $dir ("", qw(logs conf htdocs perl)) {
mkdir "$ServerRoot/$dir", 0755;
}
require File::Copy;
File::Copy::cp($0, "$ServerRoot/conf");
}
if(-e "$ServerRoot/startup.pl") {
$PerlRequire = "startup.pl";
}
$User = getpwuid($>) || $>;
$Group = getgrgid($)) || $);
$ServerAdmin = $User;
$ServerName = `hostname`;
$DocumentRoot = "$ServerRoot/htdocs";
my $types = "$ServerRoot/conf/mime.types";
$TypesConfig = -e $types ? $types : "/dev/null";
push @Alias,
["/perl" => "$ServerRoot/perl"],
["/icons" => "$ServerRoot/icons"];
my $servers = 3;
for my $s (qw(MinSpareServers MaxSpareServers StartServers MaxClients)) {
$$s = $servers;
}
for my $l (qw(LockFile ErrorLog TransferLog PidFile ScoreBoardFile)) {
$$l = "logs/$l";
#clean out the logs
local *FH;
open FH, ">$ServerRoot/$$l";
close FH;
}
my @mod_perl_cfg = qw{
SetHandler perl-script
Options +ExecCGI
};
$Location{"/perl-status"} = {
@mod_perl_cfg,
PerlHandler => "Apache::Status",
};
$Location{"/perl"} = {
@mod_perl_cfg,
PerlHandler => "Apache::Registry",
};
use Apache::PerlSections ();
Apache::PerlSections->store("$ServerRoot/ServerConfig.pm");
__END__ </Perl>
Show Contents Previous Page Next Page Copyright © 1999 by O'Reilly & Associates, Inc. |