MacDevCenter    
 Published on MacDevCenter (http://www.macdevcenter.com/)
 See this if you're having trouble printing code examples


Build Your Own Apache Server with mod_perl and mod_ssl

by David Wheeler
12/18/2002

In part one of this article I discussed some of the issues with Mac OS X's default Apache install, and how we can get around those issues through the tried-and-true approach of compiling Apache yourself. Now I'd like to go back and guide you through the process of including support for mod_ssl in your custom build of Apache.

mod_ssl is an Apache module that provides cryptographically secure connections via the Secure Sockets Layer (SSL). Any time you connect to a site and the lock icon in your browser's status bar is active, the browser has established an SSL connection to the server. Most often, the connection scheme in the URL changes from "http" to "https", for secure hypertext transport protocol. Just about any site providing commerce transactions provides SSL connectivity for sending credit card numbers and such; you would be well advised to steer clear of those that don't.

The upshot is that SSL support is a necessity for serious Internet developers, so it makes sense to add SSL to our custom-built Apache Web server. For those who use Apple's default Apache, you can use the Apache-SSL library, libssl, which is included as a dynamically loadable module. See Kevin Hemenway's "Apache Web-Serving with Mac OS X, Part 6" for some tips on using Apple's Apache modules. Of course, the same caveats I mentioned in part one of this article still apply. So for those who want to take advantage of a custom-built Apache Web server, follow me!

Preparation

If you followed the instructions in part one, we can pick up right where we left off. We'll just be adding more to the sources and compiling Apache again. The work we did last time won't get in the way, and you don't have to start over from scratch.

But you may want to consider doing so anyway, as there has been a new release of Apache since part one of this article was published. Version 1.3.27 addresses three security vulnerabilities and features numerous bug fixes and new or improved features. See the Apache release announcement for a complete list of recent changes. I will be using Apache version 1.3.27 in all of the examples in this article.

If you haven't read part one, please do so now. To save time, you can follow all of the instructions through to the installation of mod_perl. Once you return here, we'll pick up at that point to compile Apache with mod_perl and some other goodies.

Mac OS X for Unix Geeks

Related Reading

Mac OS X for Unix Geeks
By Brian Jepson, Ernest E. Rothman

A Fix for DBM Support

At this point, you should have Perl installed per Apple's instructions, downloaded and unpacked Apache in /usr/local, and configured and installed mod_perl (although in truth, if you don't want or need mod_perl support, you can just download the Apache sources and start from there). We have one minor task to get out of the way before we start configuring mod_ssl and that's to patch Apache again.

If you've done this before you'll be familiar with the headaches of getting it to work with Berkeley DB, also known as DBM. DBM is a lightweight database library required by mod_ssl and included with Mac OS X. However, an attempt to configure Apache with mod_ssl would fail with errors such as this:

/usr/bin/ld: can't locate file for: -ldbm

The apparent solution to this problem was to install GDBM, the GNU DBM library, and go from there. The problem was that other applications seemed to find and link in Apple's DBM without problem. Take Perl 5.8.0, for example. When running its test suite, Mac OS X users will see this message:

ext/DB_File/t/db-btree...............#
# This test is known to crash in Mac OS X versions 10.1.5 (or earlier)
# because of the buggy Berkeley DB version included with the OS.
#
FAILED at test 0

Although it was a "buggy" DBM, at least Perl could find it. Apache with mod_ssl, it seemed, could not. But plans to write this article motivated me to chase the problem down, and thanks to the assistance of my colleagues on the macosx@perl.org mail list, and especially Ken Williams, I traced the problem to a setting in Apache's Configure file. The fix is quite simple, and has been reported to the Apache project, as well as to Apple (Radar #3109002). It may well be fixed in a future release of Apache or of the Apple compiler. In the meantime, I've posted the fix on my web site, and now we need to apply it.

% curl -O http://david.wheeler.net/macosx/apache_dbm.patch
% cd apache_1.3.27
% patch -p0 < ../apache_dbm.patch
% cd ..

As in the first article, I use curl to download the patch. I then move into the Apache source code directory and use the patch program to apply the patch to the Apache sources. As with the apreq patch discussed in part one, the DBM patch modifies the Apache sources so that they will properly configure and compile with DBM support on Mac OS X.

In truth, the DBM bug that Perl's tests identify is relatively obscure, so using the Mac OS X DBM is fairly safe (and may well be fixed in a future Apple update). But if you're concerned about the bugginess of the Mac OS X DBM library, you can still install GDBM and use it. Ignore the patch above, and follow this procedure to install GDBM:

% curl -O ftp://ftp.gnu.org/gnu/gdbm/gdbm-1.8.3.tar.gz
% tar zxvf gdbm-1.8.3.tar.gz
% cd gdbm-1.8.3
% cp /usr/share/libtool/config* .
% ./configure
% make
% sudo make install
% sudo ln -s /usr/local/lib/libgdbm.a \
  /usr/local/lib/libdbm.a
% cd ..

Once I use curl to grab the GDBM source tarball (check the GNU FTP server for the latest release), I unpack it with tar and then move into the source directory. Next I copy Mac OS X's config.guess and config.sub files into the GDBM source directory so that configure can find the resources it needs to build GDBM. On Mac OS X 10.1.x, copy /usr/libexec/config*, instead. Next, I build and install GDBM with make and make install. The last step is the creation of a symlink. A symlink is like an Alias in the Macintosh Finder: it's another name for an existing file. In this case we create libdbm.a to point to libgdbm.a, since most applications (including Apache/mod_ssl) will look for DBM by that name.

An Optional Install

Now it's time to get busy. First, you might want to consider installing MM. This library, by mod_ssl author Ralf S. Engelschall, allows mod_ssl to share memory between forked Apache child processes, thereby optimizing the performance of mod_ssl. However, mod_ssl doesn't require MM to work; without MM, mod_ssl will use disk files to share data between Apache processes, an approach that works fine in a development environment. Unless optimal mod_ssl performance is mandatory, you needn't install MM. But if you do need MM or want it, it is fortunately easy to build and install on Mac OS X.

% curl -O ftp://ftp.ossp.org/pkg/lib/mm/mm-1.2.1.tar.gz
% tar zxvf mm-1.2.1.tar.gz
% cd mm-1.2.1
% ./configure --disable-shared
% make
% cd ..

Once I download the MM sources and untar them, as usual (check the MM site for the latest release), I change into new directory and configure MM. The INSTALL file recommends the use of the --disable-shared option to simplify installation. Once configure has found all the data it needs, make quickly compiles the needed library files. There's no need to make install, as we'll be telling Apache's configure where to find the sources so that it can link them in.

Configuring mod_ssl

Next we need to download and configure mod_ssl. You must be careful to select the proper version of mod_ssl, as each is specific to a release of the Apache Web server. Thus the mod_ssl source tarball has two version numbers in its file name. For example, the tarball I'm using for this article is mod_ssl-2.8.12-1.3.27.tar.gz; note the two separate version numbers, "2.8.12" and "1.3.27". The first is the version number for mod_ssl itself. You'll generally want to download the latest version in order to take advantage of the latest bug fixes and security updates. The second number is the Apache version number. This number must be the same as the version of Apache you're building. Since I'm using Apache version 1.3.27 here, I've downloaded the latest version of mod_ssl with "1.3.27" as its second version number. Check the mod_ssl web site for the latest version relevant to the version of Apache you're building.

% curl -O http://www.modssl.org/source/mod_ssl-2.8.12-1.3.27.tar.gz
% tar zxvf mod_ssl-2.8.12-1.3.27.tar.gz

Once again, I take the familiar approach to downloading and unpacking the mod_ssl tarball. But we need to make one more special change before we follow through on the configuration of mod_ssl.

In the past people who wanted to build Apache with mod_ssl had to first download, configure, and build OpenSSL. But since Apple already includes OpenSSL with Mac OS X, I was once again motivated in the process of writing this article to determine how to get mod_ssl to use the Apple-supplied OpenSSL library. After a bit of investigation, I figured out where the problem was and created a very simple patch to fix it. I then submitted the patch to the mod_ssl development community, so it may well be fixed in a future version of mod_ssl. In the meantime, you can patch and build mod_ssl yourself by following these steps:

% curl -O http://www.justatheory.com/computers/os/macosx/mod_ssl_dylib.patch
% cd mod_ssl-2.8.12-1.3.27
% patch -p0 < ../mod_ssl_dylib.patch
% ./configure --with-apache=../apache_1.3.27
% cd ..

Using the trusty curl utility, I download the mod_ssl patch; I then change into the mod_ssl source directory and use patch to apply the patch. The patch is fortunately trivial, simply updating the mod_ssl configuration to properly find the Mac OS X OpenSSL libraries. I then configure mod_ssl using the --with-apache option so that mod_ssl can do its thing with the Apache sources.

Security-conscious developers should be aware that Mac OS X's OpenSSL suffers from the same drawback as other Apple-supplied libraries: it tends to quickly become out-of-date. As of this writing, for example, the OpenSSL libraries included with Mac OS X 10.2.2 are at version 0.9.6e:

% openssl version
OpenSSL 0.9.6e 30 Jul 2002

Meanwhile, the current release of OpenSSL is 0.9.6g (with 0.9.7 in beta testing). Since new releases of OpenSSL generally address security issues, you may wish to download and build the latest release of OpenSSL, anyway. In most development environments, this isn't a serious issue. But if you plan to put your Mac OS X-based Apache/mod_ssl server into production in a public environment where security is of paramount concern, I recommend that you use the latest OpenSSL libraries. Fortunately, doing so is straight-forward, if time-consuming:

% curl -O http://www.openssl.org/source/openssl-0.9.6g.tar.gz
% tar zxvf openssl-0.9.6g.tar.gz
% cd openssl-0.9.6g
% ./config
% make
% make test
% sudo make install
% cd ..

Following the usual download and unpacking of the tarball, I run config with no arguments, and then run make to build OpenSSL. This will take a fairly long time, as OpenSSL is a large and complex set of libraries. On the other hand, the make test and make install commands are actually optional; Apache/mod_ssl just needs to be able to find the OpenSSL libraries in the OpenSSL source directory; they don't have to be installed. Also, be aware that make test will fail, as some of the tests are broken on Mac OS X. This issue has been addressed in the 0.9.7 beta release of OpenSSL.

Building Apache

Of course the last step is to build Apache itself. Before doing so, we'll need to set some environment variables so that it can find the OpenSSL and optional MM libraries.

% setenv SSL_BASE SYSTEM
% setenv EAPI_MM ../mm-1.2.1

The first environment variable we set, SSL_BASE, tells the Apache/mod_ssl configuration process where to find the OpenSSL library files. We set it to "SYSTEM" as a way of telling configure to find the OpenSSL library files where they have been installed as part of the operating system. If you've compiled OpenSSL yourself, you'll need to set the SSL_BASE environment variable to point to the location of the OpenSSL source directory, instead:

% setenv SSL_BASE ../openssl-0.9.6g

The second environment variable simply tells the Apache/mod_ssl configuration process where to find the MM library files. If you opted not to use MM to optimize the performance of mod_ssl, then simply omit this environment variable.

The above syntax assumes that you're using the the tcsh shell, which is the default command interpreter on Mac OS X. If you're using bash or zsh instead of tcsh, you'll need to set the environment variables with the export command:

% export SSL_BASE=SYSTEM
% export EAPI_MM=../mm-1.2.1

If you're not sure what shell you're using, type the command echo $SHELL to find out.

At last we're ready to configure and build Apache. Here are the commands to do it:

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

Apache's configure uses quite a number of options. As I mentioned in part one, the --with-layout=Apache option sets up Apache to be installed with its usual file system layout. The --enable-module=so option enables dynamically-loadable library support, while --enable-module=ssl and --enable-shared=ssl enable mod_ssl as a dynamically-loadable module. If you'd rather have mod_ssl statically compiled into Apache, omit the --enable-shared=ssl option. The --activate-module=src/modules/perl/libperl.a and --disable-shared=perl options activate mod_perl as a statically compiled module. I include these options here for parity with part one of this article; if you opted to build Apache without mod_perl (why would you want to do that?), then omit these two options. And finally, the --without-execstrip option is once again required on Mac OS X to prevent the Apache binary from being stripped. The make command of course compiles Apache.

Creating a Certificate

Once make has finished building Apache, it will print out a message that reads, in part:

Before you install the package you now should prepare the SSL certificate system by running the 'make certificate' command.

In order to use secure sockets with our Apache build, we'll need to create or set up the certificate and key that will be used to encrypt and certify the secure communications. The simplest option, and the one that makes the most sense if you're just getting started working with mod_ssl in a development environment, is to use the TYPE=dummy option to create a dummy certificate suitable for a non-production setting. If you're planning to use your Apache/mod_ssl server to develop Internet applications, this is the easiest option for getting up and running:

% make certificate TYPE=dummy

In a production setting, it makes more sense to purchase a signed certificate from a known certificate authority such as VeriSign or GeoTrust. In that case, you'll want to use the TYPE=existing option along with the CRT and KEY options to configure your new Apache build to use the certificate and keys provided by your certificate authority:

% make certificate TYPE=existing \
  CRT=/path/to/server.crt \ 
  KEY=/path/to/server.key

And finally, if you'd like to create your own, self-signed certificate, you can use the TYPE=custom option. This option will prompt you to answer a series of questions and will create a new custom certificate for you. Note that it will ask for much the same information twice -- once for the Certificate Authority (CA) and once for the server certificate. Just be sure to enter different values for the "Organization Unit Name" for each, as the certificate authority and the owner of the server certificate cannot have the same organizational unit name. You will also be prompted to encrypt the certificate and key.

In general, it's a good idea to encrypt them in a multi-user environment. But in a controlled environment where only trusted users have access to the server (such as the majority of Mac OS X computers), it's not necessary to encrypt the keys. If you do decide to encrypt the keys, note that you will be prompted to enter a passphrase every time you start the Apache/mod_ssl server. Refer to the mod_ssl manual for more information.

Installation

Once you've finished configuring and building Apache and you've created and configured your SSL certificate, you can install Apache. Note that if you have an existing custom installation of Apache (because, for example, you built it according to the instructions in part one of this article), that version will be overwritten when you install the new build. I therefore recommend that you first move your existing Apache build out of the way.

% sudo mv /usr/local/apache /usr/local/apache.saf
% sudo make install
% cd ..

Following my own advice, I first move my existing Apache build out of the way by renaming the directory in which it is stored from apache to apache.saf. Then, make install installs the new build.

Testing Your New Apache Build

Yep, that was it. The new build of Apache with mod_ssl should be completely installed in /usr/local/apache. A quick test confirms that the installation was successful:

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

We use the same command as in part one to make sure that Apache can load its configuration file without error. And again, we can try running Apache and connecting from a web browser. Execute this command:

% 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 name ("localhost" will probably work fine). If you see a page that starts with, "Hey, it worked!", then you know that Apache was successfully installed and works on your Mac.

Testing mod_ssl

Finally, we want to test the mod_ssl interface to make sure that it's working properly. Apache makes it very simple to use mod_ssl by providing the startssl startup command to apachectl:

% sudo /usr/local/apache/bin/apachectl stop 
/usr/local/apache/bin/apachectl stop: httpd stopped
% sudo /usr/local/apache/bin/apachectl startssl
/usr/local/apache/bin/apachectl startssl: httpd started

Now point your browser to your Mac again and check for "Hey, it worked!" This demonstrates that Apache is still working as normal. Now change the scheme for the URL in your browser from "http" to "https" to connect via SSL. If you've configured Apache/mod_ssl to use a certificate from a known certificate authority, you should be able to connect and see the same page as before. If you created a custom certificate, you will likely be prompted by your browser with a message to the affect of "This site has an identity that cannot be verified." Just agree to connect, since you can probably trust yourself. And if you created a dummy certificate, your browser may prompt you multiple times. Mine offered each of the following prompts in sequence:

Just accept each of them and ultimately you should see the same test page as before

What if the browser gave you a "connection refused" error? This is more than likely because you neglected to move your old Apache build out of the way. Well, even the best of us sometimes don't follow our own good advice. The new build of Apache has created a new configuration file, but did not replace your existing configuration file. So all you need to do to get your new mod_ssl build of Apache to server via SSL is to swap the configuration files:

% sudo /usr/local/apache/bin/apachectl stop
/usr/local/apache/bin/apachectl stop: httpd stopped
% sudo mv /usr/local/apache/conf/httpd.conf \
  /usr/local/apache/conf/httpd.conf.old
% sudo mv /usr/local/apache/conf/httpd.conf.default \
  /usr/local/apache/conf/httpd.conf
% sudo /usr/local/apache/bin/apachectl startssl
/usr/local/apache/bin/apachectl startssl: httpd started

Now try to connect to your new Apache/mod_ssl server via "https", and say hello to the friendly default page with its "Hey, it worked!" message.

Rejoice. Your Apache with mod_ssl is now ready for use.

Apache Startup Bundle Redux

In part one of this article, I provided instructions for creating a startup bundle so that your custom Apache could be started when Mac OS X starts. My approach to creating the bundle involved copying Apple's Apache startup bundle from /System/Library/StartupItems, altering it, and then putting it into /Library/StartupItems.

However, attentive reader Milo Polten noticed a flaw in my approach -- at least from the point of view of good Mac OS X system administration. I had suggested that all of the if statements be removed from our copy of the Mac OS X Apache startup script, since they tested the value of the $WEBSERVER variable, which is set via the "Personal Web Sharing" check box in the "Sharing" system preference. It turns out, however, that the check box is just a convenient way for users to actually change the value of the $WEBSERVER entry in the /etc/hostconfig file, and it is actually this file that offers a Darwin-like method for enabling and disabling startup scripts.

The general idea is that all Mac OS X system startup scripts are controlled by the presence of variables in the /etc/hostconfig file, and the scripts themselves are supposed to check for the proper variable setting in that file. Thus startup services can be enabled or disabled merely by editing /etc/hostconfig, rather than by moving startup bundles in and out of /System/Library/StartupItems or /Library/StartupItems.

As a result of my newly-gained knowledge, I'd like to suggest a new approach to creating an Apache startup bundle. First, copy Apple's startup bundle to a temporary location:

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

Now, using your favorite editor (TextEdit will work fine), open up the ~/Desktop/Apache/Apache file. Again, change all instances of apachectl to point to our new Apache server controller, /usr/local/apache/bin/apachectl. However, do not delete the if statements. Instead, change the name of the variable to be checked from WEBSERVER to APACHESERVER. The resulting file should look 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"

If you'd like Apache to start up with ssl support, change /usr/local/apache/bin/apachectl start to /usr/local/apache/bin/apachectl startssl.

Next, add the $APACHESERVER variable to /etc/hostconfig. 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 the test page loads. If it does, you're in business, and the Apache server will be started whenever you boot into Mac OS X.

Good to Go

There you have it, everything you need to know about how to compile your own Apache Web server with mod_perl and mod_ssl. The instructions I've provided in the two parts of this article should give you the knowledge you need to compile Apache with just about any module you're likely to need in your Internet development work. Other modules you may wish to consider include mod_php for PHP language support; mod_tcl for TCL language support; and mod_dav for WebDAV (distributed authoring and versioning) support. See the Apache Module Registry for a comprehensive list of modules. And enjoy your total Internet development environment: Mac OS X.

David Wheeler is a developer at Portland, Oregon-based Values of n, where he writes the code that makes Stikkit's little yellow notes think.


Return to the Mac DevCenter.


Copyright © 2009 O'Reilly Media, Inc.