12.3 One Plain and One mod_perl-Enabled Apache Server

As mentioned earlier, when running scripts under mod_perl you will notice that the httpd processes consume a huge amount of virtual memory?from 5 MB-15 MB, and sometimes even more. That is the price you pay for the enormous speed improvements under mod_perl, mainly because the code is compiled once and needs to be cached for later reuse. But in fact less memory is used if memory sharing takes place. Chapter 14 covers this issue extensively.

Using these large processes to serve static objects such as images and HTML documents is overkill. A better approach is to run two servers: a very light, plain Apache server to serve static objects and a heavier, mod_perl-enabled Apache server to serve requests for dynamically generated objects. From here on, we will refer to these two servers as httpd_docs (vanilla Apache) and httpd_perl (mod_perl-enabled Apache). This approach is depicted in Figure 12-2.

Figure 12-2. Standalone and mod_perl-enabled Apache servers
figs/pmp_1202.gif

The advantages of this setup are:

  • The heavy mod_perl processes serve only dynamic requests, so fewer of these large servers are deployed.

  • MaxClients, MaxRequestsPerChild, and related parameters can now be optimally tuned for both the httpd_docs and httpd_perl servers (something we could not do before). This allows us to fine-tune the memory usage and get better server performance.

    Now we can run many lightweight httpd_docs servers and just a few heavy httpd_perl servers.

The disadvantages are:

  • The need for two configuration files, two sets of controlling scripts (startup/shutdown), and watchdogs.

  • If you are processing log files, you will probably have to merge the two separate log files into one before processing them.

  • Just as in the one-server approach, we still have the problem of a mod_perl process spending its precious time serving slow clients when the processing portion of the request was completed a long time ago. (Deploying a proxy, covered in the next section, solves this problem.)

    As with the single-server approach, this is not a major disadvantage if you are on a fast network (i.e., an Intranet). It is likely that you do not want a buffering server in this case.

Note that when a user browses static pages and the base URL in the browser's location window points to the static server (for example http://www.example.com/index.html), all relative URLs (e.g., <a href="/main/download.html">) are being served by the plain Apache server. But this is not the case with dynamically generated pages. For example, when the base URL in the location window points to the dynamic server (e.g., http://www.example.com:8000/perl/index.pl), all relative URLs in the dynamically generated HTML will be served by heavy mod_perl processes.

You must use fully qualified URLs, not relative ones. http://www.example.com/icons/arrow.gif is a full URL, while /icons/arrow.gif is a relative one. Using <base href="http://www.example.com/"> in the generated HTML is another way to handle this problem. Also, the httpd_perl server could rewrite the requests back to httpd_docs (much slower) and you still need the attention of the heavy servers.

This is not an issue if you hide the internal port implementations, so the client sees only one server running on port 80, as explained later in this chapter.

12.3.1 Choosing the Target Installation Directories Layout

If you're going to run two Apache servers, you'll need two complete (and different) sets of configuration, log, and other files. In this scenario we'll use a dedicated root directory for each server, which is a personal choice. You can choose to have both servers living under the same root, but this may cause problems since it requires a slightly more complicated configuration. This decision would allow you to share some directories, such as include (which contains Apache headers), but this can become a problem later, if you decide to upgrade one server but not the other. You will have to solve the problem then, so why not avoid it in the first place?

First let's prepare the sources. We will assume that all the sources go into the /home/stas/src directory. Since you will probably want to tune each copy of Apache separately, it is better to use two separate copies of the Apache source for this configuration. For example, you might want only the httpd_docs server to be built with the mod_rewrite module.

Having two independent source trees will prove helpful unless you use dynamically shared objects (covered later in this chapter).

Make two subdirectories:

panic% mkdir /home/stas/src/httpd_docs
panic% mkdir /home/stas/src/httpd_perl

Next, put the Apache source into the /home/stas/src/httpd_docs directory (replace 1.3.x with the version of Apache that you have downloaded):

panic% cd /home/stas/src/httpd_docs
panic% tar xvzf ~/src/apache_1.3.x.tar.gz

Now prepare the httpd_perl server sources:

panic% cd /home/stas/src/httpd_perl
panic% tar xvzf ~/src/apache_1.3.x.tar.gz
panic% tar xvzf ~/src/modperl-1.xx.tar.gz

panic% ls -l
drwxr-xr-x  8 stas  stas 2048 Apr 29 17:38 apache_1.3.x/
drwxr-xr-x  8 stas  stas 2048 Apr 29 17:38 modperl-1.xx/

We are going to use a default Apache directory layout and place each server directory under its dedicated directory. The two directories are:

/home/httpd/httpd_perl/
/home/httpd/httpd_docs/

We are using the user httpd, belonging to the group httpd, for the web server. If you don't have this user and group created yet, add them and make sure you have the correct permissions to be able to work in the /home/httpd directory.

12.3.2 Configuration and Compilation of the Sources

Now we proceed to configure and compile the sources using the directory layout we have just described.

12.3.2.1 Building the httpd_docs server

The first step is to configure the source:

panic% cd /home/stas/src/httpd_docs/apache_1.3.x
panic%  ./configure --prefix=/home/httpd/httpd_docs \
    --enable-module=rewrite --enable-module=proxy

We need the mod_rewrite and mod_proxy modules, as we will see later, so we tell ./configure to build them in.

You might also want to add ?layout, to see the resulting directories' layout without actually running the configuration process.

Next, compile and install the source:

panic% make
panic# make install

Rename httpd to httpd_docs:

panic% mv /home/httpd/httpd_docs/bin/httpd \
    /home/httpd/httpd_docs/bin/httpd_docs

Now modify the apachectl utility to point to the renamed httpd via your favorite text editor or by using Perl:

panic% perl -pi -e 's|bin/httpd|bin/httpd_docs|' \
    /home/httpd/httpd_docs/bin/apachectl

Another approach would be to use the ?target option while configuring the source, which makes the last two commands unnecessary.

panic% ./configure --prefix=/home/httpd/httpd_docs \
    --target=httpd_docs \
    --enable-module=rewrite --enable-module=proxy
panic% make
panic# make install

Since we told ./configure that we want the executable to be called httpd_docs (via ?target=httpd_docs), it performs all the naming adjustments for us.

The only thing that you might find unusual is that apachectl will now be called httpd_docsctl and the configuration file httpd.conf will now be called httpd_docs.conf.

We will leave the decision making about the preferred configuration and installation method to the reader. In the rest of this guide we will continue using the regular names that result from using the standard configuration and the manual executable name adjustment, as described at the beginning of this section.

12.3.2.2 Building the httpd_perl server

Now we proceed with the source configuration and installation of the httpd_perl server.

panic% cd /home/stas/src/httpd_perl/mod_perl-1.xx

panic% perl Makefile.PL \
    APACHE_SRC=../apache_1.3.x/src \
    DO_HTTPD=1 USE_APACI=1 EVERYTHING=1 \
    APACHE_PREFIX=/home/httpd/httpd_perl \
    APACI_ARGS='--prefix=/home/httpd/httpd_perl'

If you need to pass any other configuration options to Apache's ./configure, add them after the ?prefix option. For example:

APACI_ARGS='--prefix=/home/httpd/httpd_perl \
            --enable-module=status'

Notice that just like in the httpd_docs configuration, you can use ?target=httpd_perl. Note that this option has to be the very last argument in APACI_ARGS; otherwise make test tries to run httpd_perl, which fails.

Now build, test, and install httpd_perl.

panic% make && make test
panic# make install

Upon installation, Apache puts a stripped version of httpd at /home/httpd/httpd_perl/bin/httpd. The original version, which includes debugging symbols (if you need to run a debugger on this executable), is located at /home/stas/src/httpd_perl/apache_1.3.x/src/httpd.

Now rename httpd to httpd_perl:

panic% mv /home/httpd/httpd_perl/bin/httpd \
    /home/httpd/httpd_perl/bin/httpd_perl

and update the apachectl utility to drive the renamed httpd:

panic% perl -p -i -e 's|bin/httpd|bin/httpd_perl|' \
    /home/httpd/httpd_perl/bin/apachectl

12.3.3 Configuration of the Servers

When we have completed the build process, the last stage before running the servers is to configure them.

12.3.3.1 Basic httpd_docs server configuration

Configuring the httpd_docs server is a very easy task. Open /home/httpd/httpd_docs/conf/httpd.conf in your favorite text editor and configure it as you usually would.

Now you can start the server with:

/home/httpd/httpd_docs/bin/apachectl start
12.3.3.2 Basic httpd_perl server configuration

Now we edit the /home/httpd/httpd_perl/conf/httpd.conf file. The first thing to do is to set a Port directive?it should be different from that used by the plain Apache server (Port 80), since we cannot bind two servers to the same port number on the same IP address. Here we will use 8000. Some developers use port 81, but you can bind to ports below 1024 only if the server has root permissions. Also, if you are running on a multiuser machine, there is a chance that someone already uses that port, or will start using it in the future, which could cause problems. If you are the only user on your machine, you can pick any unused port number, but be aware that many organizations use firewalls that may block some of the ports, so port number choice can be a controversial topic. Popular port numbers include 80, 81, 8000, and 8080. In a two-server scenario, you can hide the nonstandard port number from firewalls and users by using either mod_proxy's ProxyPass directive or a proxy server such as Squid.

Now we proceed to the mod_perl-specific directives. It's a good idea to add them all at the end of httpd.conf, since you are going to fiddle with them a lot in the early stages.

First, you need to specify where all the mod_perl scripts will be located. Add the following configuration directive:

# mod_perl scripts will be called from
Alias /perl /home/httpd/httpd_perl/perl

From now on, all requests for URIs starting with /perl will be executed under mod_perl and will be mapped to the files in the directory /home/httpd/httpd_perl/perl.

Now configure the /perl location:

PerlModule Apache::Registry

<Location /perl>
    #AllowOverride None
    SetHandler perl-script
    PerlHandler Apache::Registry
    Options ExecCGI
    PerlSendHeader On
    Allow from all
</Location>

This configuration causes any script that is called with a path prefixed with /perl to be executed under the Apache::Registry module and as a CGI script (hence the ExecCGI?if you omit this option, the script will be printed to the user's browser as plain text or will possibly trigger a "Save As" window).

This is only a very basic configuration. Chapter 4 covers the rest of the details.

Once the configuration is complete, it's a time to start the server with:

/home/httpd/httpd_perl/bin/apachectl start


    Part I: mod_perl Administration
    Part II: mod_perl Performance
    Part VI: Appendixes