90 Build Your Own Apache Server with mod_perl





Build Your Own Apache Server with mod_perl

figs/expert.giffigs/hack90.gif

Go beyond the capabilities of the Apple-supplied Apache web server, building your own version with mod_perl for scalable web applications built in Perl.

When Apple released Mac OS X, it included as part of the operating system one of the most powerful and most used applications on the Internet today: the Apache web server. This has been a boon for Mac users and dedicated Unix jocks alike, as the combination of Apache's simplicity and power and the legendary Mac OS ease-of-use has made for a robust Internet application development platform. Largely due to the inclusion of Apache, along with a host of other necessary Unix power tools, Mac OS X has rapidly become the Unix developer's platform of choice.

And lest anyone be concerned, the Apache that ships with Mac OS X is the genuine article. We're not talking about a weak, proof-of-concept port of Apache that runs under Windows. Mac OS X's FreeBSD underpinnings allow for the Apache web server to be as flexible and responsive as it is on any Unix-based operating system. See [Hack #51] to get started web serving using Apache.

However, the version of Apache included with Mac OS X is arguably unsatisfactory in a number of ways. If you're like me and plan to do some serious mod_perl-based web development work on Mac OS X, you'll need to take the following issues into consideration as you begin working with Apple's Apache install:

  • Although it includes support for mod_perl, it is as a dynamically loadable library (dynlib), which means that Perl can be dynamically loaded into the Apache binary at startup time. Unfortunately, a quick search of the mod_perl users mail list (http://mathforum.org/epigone/modperl) or the HTML::Mason users list (http://sourceforge.net/mailarchive/forum.php?forum_id=5219) archives reveals that the dynamically loadable mod_perl is notoriously unstable. As a result, most serious mod_perl users prefer to statically compile mod_perl right into the Apache binary.

  • The version of Perl supported by Apple's Apache is the same as that included with Mac OS X: 5.6.0. Although Apple has provided instructions on how to compile the newer, more robust Perl 5.8.0 yourself (http://developer.apple.com/internet/macosx/perl.html), doing so won't automatically make mod_perl use Perl 5.8.0. You have to compile mod_perl yourself to get the latest and greatest.

  • Although new versions of Apache are regularly released to fix bugs or patch security holes, Mac OS X users must wait for an OS update from Apple to enjoy the benefits of the latest releases. That time lag can leave OS X Apache users exposed to known security issues until Apple provides an update.

For those whose web-serving needs have exceeded the capabilities of the Apple-supplied Apache, and for those who need to develop scalable web applications built on Perl 5.8.0 and mod_perl, an important alternative exists: you can build your own Apache web server on Mac OS X. In this hack, I guide you through the steps necessary to build your own Apache server with mod_perl.

Preparation

Compiling your own applications means that you need a compiler. Apple kindly offers one with the Mac OS X Developer Tools [Hack #55].

If we're to install Apache with mod_perl, the first thing we need to do is install the latest version of Perl. Fortunately, Apple has provided the aforementioned instructions for downloading and compiling Perl 5.8.0 (http://developer.apple.com/internet/macosx/perl.html). Although that article documents compiling Perl 5.8.0 on Jaguar, it should work reasonably well on Mac OS X 10.1.x, as well.

Next, we'll need to download the latest Apache 1.3 and mod_perl 1.x sources. You can find the Apache sources on the Apache HTTP Server Source Code Distributions page (http://www.apache.org/dist/httpd/) or at your nearest mirror (http://www.apache.org/dyn/closer.cgi/httpd/). As I write this, the latest version is 1.3.27, so that's what I'll use in the remainder of this article. The latest version of mod_perl is available from the mod_perl distribution page (http://perl.apache.org/dist/).

I also recommend that you grab the libapreq sources from their home page (http://httpd.apache.org/apreq/). The libapreq library provides some useful mod_perl-related modules for which I also include installation instructions. As of this writing, the latest libapreq version is 1.1, so that's the version you'll see in all the following examples:

% cd /usr/local/src
% curl -O http://www.apache.org/dist/httpd/apache_1.3.27.tar.gz
% tar zxvf apache_1.3.27.tar.gz
% curl -O http://perl.apache.org/dist/mod_perl-1.0-current.tar.gz
% tar zxvf mod_perl-1.0-current.tar.gz
% curl -O \
  ftp://ftp.cpan.org/pub/CPAN/authors/id/J/JI/JIMW/libapreq-1.1.tar.gz
% tar zxvf libapreq-1.1.tar.gz

Following Apple's example, I move into the /usr/local/src directory and do all of the work there. I've used the handy curl utility to download the Apache and mod_perl sources right in my Terminal session. I then used the tar program to unpack the sources. The Apache sources will now be in the directory apache_1.3.27/, while the mod_perl sources will be in the directory mod_perl-1.xx/ and the libapreq sources will be in the directory libapreq-1.1/. As of this writing, the current version of mod_perl is 1.27, so I'll be working in the mod_perl-1.27/ directory in the following examples.

Building mod_perl

Now, we're ready to start building the software. At this point, you should have downloaded, compiled, and installed Perl according to the instructions from Apple (with the source code still living in /usr/local/src/perl-5.8.0) and followed the steps outlined earlier in this hack. Next, we'll build mod_perl.

Like most source-code installations, mod_perl offers a good number of configuration options. A quick perusal of the installation guide (http://perl.apache.org/docs/1.0/guide/install.html) reveals all. However, I'm going to recommend a relatively straightforward configuration that includes support for all of the mod_perl features you're likely to need, while allowing the flexibility to build other Apache modules into Apache later on. Here it is:

% cd ../mod_perl-1.27
% perl Makefile.PL \
APACHE_SRC=../apache_1.3.27/src \
NO_HTTPD=1 \
USE_APACI=1 \
PREP_HTTPD=1 \
EVERYTHING=1

The perl script Makefile.PL creates the Makefile that will be used to compile mod_perl. The APACHE_SRC option tells Makefile.PL where to find the Apache sources. The NO_HTTPD option, meanwhile, forces the build process to use this path but keeps it from compiling Apache before we're ready. The USE_APACI option is what allows that flexibility, as it enables mod_perl's hybrid build environment, wherein we can later compile other modules into Apache. Meanwhile, the PREP_HTTPD option triggers the build process to set up the Apache sources for mod_perl by preparing the APACHE_SRC/modules/perl/ directory tree. But we save the most important option for last. The EVERYTHING option enables all of mod_perl's features.

When this command runs, you'll be prompted to configure mod_perl with the APACHE_SRC sources. Do so by simply pressing the Return key. At this point, mod_perl's configuration will quickly take care of all of its tasks without further intervention.

Next, we'll build and install mod_perl. Fortunately, the tricky part is over. All we need to do is this:

% make
% sudo make install

These two steps build mod_perl and install it. But before we can take advantage of the newly installed mod_perl, we need to configure and build Apache.

Building Apache

The Apache configuration process offers a bewildering array of options, all of which are documented in the INSTALL file included with the Apache sources. Of course, I'll try to keep things simple enough to get the job done with the tools we need.

% ./configure \
--with-layout=Apache \
--enable-module=so \
--activate-module=src/modules/perl/libperl.a \
--disable-shared=perl \
--without-execstrip

Once again, the configuration is the most complex part of the process. The --with-layout=Apache option sets up Apache to be installed with its usual filesystem layout (i.e., in the /usr/local/apache directory). The --enable-module=so option enables dynamically loadable library support, should you decide later to build and use any third-party modules as dynamically loadable objects. The --activate-module=src/modules/perl/libperl.a option activates mod_perl, while the --disable-shared=perl option forces Apache to compile in mod_perl statically, rather than as a dynamically loadable library. And finally, the --without-execstrip option is required on Mac OS X to prevent the Apache binary from being stripped (whatever that means).

After configure does its job, we compile and install Apache with the usual commands:

% make
% sudo make install

Testing Your New Apache Build

Now, Apache is completely compiled and installed with mod_perl. A quick test confirms that the installation was successful:

% sudo /usr/local/apache/bin/apachectl configtest
Syntax OK

This quick test confirms that Apache compiled properly and loads its default configuration file without error. But it's more interesting to actually get it to serve some web pages. First, make sure that Apple's version of Apache isn't running, by disabling Personal Web Sharing in the Sharing global system preference. Then, start up your newly compiled version of Apache:

% sudo /usr/local/apache/bin/apachectl start
/usr/local/apache/bin/apachectl start: httpd started

Now, fire up your favorite browser and type in your Mac's domain name ("localhost" should do the trick). If you see a page that starts with "Hey, it worked!" you're in business.

Testing mod_perl

As the final part of this process, we confirm to ourselves for the sake of our own sanity that mod_perl is functioning properly, too. Fortunately, this is rather simple to do, as mod_perl includes a module we can easily use for this purpose. The Apache::Status module is designed to display information about the status of your Apache web server, as well as mod_perl itself. To use it, simply edit the default Apache configuration file [Hack #89], /usr/local/apache/conf/httpd.conf, and add these lines to it:

PerlModule Apache::Status
<Location /perl-status>
  SetHandler perl-script
  PerlHandler Apache::Status
</Location>

Restart Apache so that it loads the new module:

% sudo /usr/local/apache/bin/apachectl restart
/usr/local/apache/bin/apachectl restart: httpd restarted

Now, hit your web server again, this time entering the perl-status directory name (e.g., http://localhost/perl-status/). You should see a page appear with something like this at the top:

Embedded Perl version v5.8.0 for Apache/1.3.27 (Darwin) mod_perl/1.27 process 12365,

running since Thu Sep 19 01:05:43 2002

Building libapreq

Now that you have a fully working custom Apache installation, you might want to consider installing libapreq. This library includes Apache::Request and Apache::Cookie (http://search.cpan.org/dist/libapreq/), two convenient Perl modules that offer much more efficient processing than their analogs in the commonly-used CGI module (http://search.cpan.org/dist/CGI.pm/). As of Version 1.1 the libapreq library is fully supported on Mac OS X 10.2, although it requires a special installation process. (Mac OS X 10.1 users should read the INSTALL.MacOSX file for an alternative approach.) If you'd like to take advantage of libapreq's efficiencies in your mod_perl server, follow these steps to install it:

% cd libapreq-1.1
% ./conFigurewith-apache-includes=/usr/local/apache/include
% make
% sudo make install 

Installing libapreq on Mac OS X is a two-step process. Here, we build and install the C library on which the Perl modules rely. The --with-apache-includes=/usr/local/apache/include option tells configure where to find the include files for our new Apache installation. Then, of course, make and make install compile and install the libapreq C library.

Next, we need to build the libapreq Perl modules. These follow the usual Perl module installation procedure:

% perl Makefile.PL
% make
% sudo make test
% sudo make install 

The Makefile.PL script will ask a series of questions and then build the Makefile that will allow us to build the Perl modules. Be sure you enter the proper location for your new Apache server when prompted; Makefile.PL will most likely find Apple's Apache at /usr/sbin/httpd and you'll need to enter /usr/local/apache/bin/httpd instead. Of course, make compiles the modules, while make test and make install test and install Apache::Request and Apache::Cookie. Be aware that make test will work only if you entered correct information when prompted by Makefile.PL and when the Perl modules LWP and URI have been installed from CPAN. The great thing about make test, in this case, is that it actually uses our Apache/mod_perl server to test the new Perl modules. This means that, if all the tests passed, Apache::Request and Apache::Cookie will be in complete working order and ready to use.

Apache Startup Bundle

Having a working Apache is all well and good but not worth much unless it's running. If you'd like your Mac OS X box to function as a web server all the time, you may want to create a startup bundle for it. Apple has documented a specification for startup bundles in its Creating System Starter Startup Item Bundles HOWTO (http://www.opensource.apple.com/projects/documentation/howto/html/SystemStarter_HOWTO.html), but it's a simple matter to adapt Mac OS X's existing Apache startup bundle for our purposes.

Apple has created the /System/Library directory structure for use by the Mac OS X operating system and the /Library directory structure for use by third-party applications such as our new Apache server. All system startup bundles, including for Apple's build of Apache, go into the /System/Library/StartupItems directory. The startup bundles for third-party applications go into the /Library/StartupItems directory. So, to adapt Apple's Apache startup bundle, we'll first copy it to a temporary location. Later, we'll move the copy to its new home:

% cp -rf /System/Library/StartupItems/Apache ~/Desktop/

This command will copy the entire Apache startup bundle directory structure to the desktop where we can easily edit it. Next, using your favorite editor (TextEdit will work fine), open the ~/Desktop/Apache/Apache file. The file should look like this:

#!/bin/sh

##
# Apache HTTP Server
##

. /etc/rc.common

StartService ()
{
    if [ "${WEBSERVER:=-NO-}" = "-YES-" ]; then
        ConsoleMessage "Starting Apache web server"
        apachectl start
    fi
}

StopService ()
{
    ConsoleMessage "Stopping Apache web server"
    apachectl stop
}

RestartService ()
{
    if [ "${WEBSERVER:=-NO-}" = "-YES-" ]; then
        ConsoleMessage "Restarting Apache web server"
        apachectl restart
    else
        StopService
    fi
}

RunService "$1"

This file is a Unix Bourne shell script and is executed whenever your Mac starts up and shuts down. There are essentially two changes we need to make to convert this script for starting our newly-compiled Apache server. First, change the location of the apachectl startup script. Just calling apachectl will cause Apple's Apache server to start up. To get our new one to start, we need to change the location to /usr/local/apache/bin/apachectl. Second, change the name of the variable to be checked in each if statement from WEBSERVER to APACHESERVER. The result of our changes to the startup script looks like this:

#!/bin/sh

##
# Apache HTTP Server
##

. /etc/rc.common

StartService ()
{
    if [ "${APACHESERVER:=-NO-}" = "-YES-" ]; then
        ConsoleMessage "Starting Apache web server"
        /usr/local/apache/bin/apachectl start
    fi
}

StopService ()
{
    ConsoleMessage "Stopping Apache web server"
    /usr/local/apache/bin/apachectl stop
}

RestartService ()
{
    if [ "${APACHESERVER:=-NO-}" = "-YES-" ]; then
        ConsoleMessage "Restarting Apache web server"
        /usr/local/apache/bin/apachectl restart
    else
        StopService
    fi
}

RunService "$1" 

Next, add the $APACHESERVER variable to /etc/hostconfig. This file contains all of the variables that are checked in the Mac OS X startup scripts, and we'll need to add ours here, since our new script checks for it. The simplest way to do this is to use the echo command on the command line to append it to the the file:

% sudo echo APACHESERVER=-YES- >> /etc/hostconfig 

You can also edit the file directly using TextEdit, but you must open TextEdit as the root user in order to be able to edit the file. You can use the sudo utility on the command line to accomplish this:

% sudo /Applications/TextEdit.app/Contents/MacOS/TextEdit /etc/hostconfig 

Once you've added the line APACHESERVER=-YES-, save your changes and quit TextEdit. Now, move the entire startup bundle to its new home in /Library/StartupItems and test it:

% sudo mv ~/Desktop/Apache /Library/StartupItems
% sudo /Library/StartupItems/Apache/Apache start
Starting Apache web server
/usr/local/apache/bin/apachectl start: httpd started 

Point your browser to your local computer again and make sure a page loads. If it does, you're in business and the Apache server will be started whenever you boot into Mac OS X. If you ever want to prevent Apache from starting at system startup, simply edit /etc/hostconfig again and change APACHESERVER=-YES- to APACHESERVER=-NO-.

—David E. Wheeler


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows