mod_perl in 30 minutes
In the previous article, I've shown quite amazing Web performance reports from companies that have deployed mod_perl heavily. You might be surprised but you can quite easily get similarly amazing results if you move your service to mod_perl as well. In fact, getting started with mod_perl shouldn't take you more than 30 minutes -- the time it takes to compile and configure the server on a decent machine and get it running.
In this article I'll show step-by-step installation and configuration scenarios, and chances are you will be able to run the basic statically compiled mod_perl setup without reading any other documents. Of course, you will want and need to read the documentation later, but I think you will agree with me that it's ultimately cool to be able to get your feet wet without knowing much about the new technology up-front.
The mod_perl installation was tested on many mainstream Unix platforms, so unless you have a nonstandard system, you shouldn't have any problems building the basic mod_perl server.
If you are a Windows user, then the easiest way is to use the binary package available from http://perl.apache.org/download/index.html. From the same location, you can download the Linux RPM version and CVS snapshots. However, I always recommend to build the mod_perl from the source, and as you will see in a moment, it's an easy thing to do.
So let's start with the installation process. If you are an experienced Unix user, then you need no explanation for the following commands. Just copy and paste them and you will get the server installed.
I'll use a %
sign as the shell program's prompt.
% cd /usr/src
Downloading the source code for the Apache web server takes a few steps. Start at http://httpd.apache.org/download.cgi. This should choose the appropriate mirror for you. Select the latest downloadable file labeled "Unix Source" with the tar.gz extension. Download it to /usr/src.
% lwp-download http://perl.apache.org/download/binaries.html % tar -zvxf apache_1.3.20.tar.gz % tar -zvxf mod_perl-1.26.tar.gz % cd mod_perl-1.26 % perl Makefile.PL APACHE_SRC=../apache_1.3.20/src \ DO_HTTPD=1 USE_APACI=1 EVERYTHING=1 % make && make test && make install % cd ../apache_1.3.20 % make install
That's all!
What's left is to add a few configuration lines to httpd.conf, an Apache configuration file, start the server and enjoy mod_perl.
If you have stumbled upon a problem at any of the above steps, then don't despair -- the next section will explain in detail each step.
If you didn't have the courage to try the steps in the previous section or you simply want to understand more before you try, then let's go through the fine details of the installation process. If you have successfully installed mod_perl following the short scenario in the previous section, then you can skip this section and move on to the next one.
Before we proceed, I should note that you have to become a root user in order to install the files in a protected area. If you don't have root access, then you can install all the files under your home directory. We will talk about the nuances of this approach in a future articles. I'll also assume that you have perl and gcc or an equivalent C compiler installed.
I assume that all builds are being done in the /home/stas/src directory. So we go into this directory.
% cd /home/stas/src
Now we download the latest source distributions of Apache and
mod_perl. If you have the LWP
module installed (also known as
libwww and available from CPAN), then you should have the
lwp-download
utility that partly imitates your favorite browser by
allowing you to download files from the Internet. You can use any
other method to retrieve these files. Just make sure that you save
both files in the /home/stas/src directory, as this will make it
easier for you to follow the example installation process. Of course,
you can install both packages anywhere on your file system.
% lwp-download http://www.apache.org/dist/httpd/apache_1.3.20.tar.gz
% lwp-download http://perl.apache.org/dist/mod_perl-1.26.tar.gz
You can make sure that you're downloading the latest stable versions by visiting the following distribution directories: http://www.apache.org/dist/httpd/ and http://perl.apache.org/dist/. As you have guessed already, the former URL is the main Apache distribution directory, the latter is the same thing for mod_perl.
Untar both sources. You have to uncompress and untar the files. In
addition to its main usage for tarring and untarring files, the GNU
tar
utility is able to uncompress files compressed by the gzip
utility, when the -z
option is used.
% tar -zvxf apache_1.3.20.tar.gz
% tar -zvxf mod_perl-1.26.tar.gz
If you have a non-GNU tar
utility, then chances are that it will be
unable to decompress, so you need to do it in two steps. First,
uncompress the packages with:
% gzip -d apache_1.3.20.tar.gz
% gzip -d mod_perl-1.26.tar.gz
Then untar them with:
% tar -xvf apache_1.3.20.tar
% tar -xvf mod_perl-1.26.tar
If you don't have tar
or gzip
utilities available, then install them or use their equivalents.
Now go into the mod_perl source distribution directory.
% cd mod_perl-1.26
The next step is to create the Makefile.
% perl Makefile.PL APACHE_SRC=../apache_1.3.20/src \
DO_HTTPD=1 USE_APACI=1 EVERYTHING=1
mod_perl accepts a variety of parameters, in this scenario we are going to use those that will allow you to do almost everything with mod_perl. Once you learn more about mod_perl, you will be able to fine-tune the list of parameters passed to Makefile.PL. In future articles, I'll go through all the available options.
perl Makefile.PL ...
execution will check for prerequisites and
tell you which required software packages are missing from your
system. If you don't have some of the Perl packages installed, then you
will have to install these before you proceed. They all are available
from CPAN and can be easily downloaded and installed.
If you choose to install mod_perl with help of the CPAN.pm
module,
then it will install all the missing modules for you. To do so, tell
CPAN.pm
to install the Bundle::Apache
bundle.
This step also executes the ./configure
script from Apache's source
distribution directory (absolutely transparently for you), which
prepares the Apache build configuration files. If you need to pass
parameters to Apache's ./configure
script, then pass them as
options to perl Makefile.PL ...
. In future articles we will talk
about all the available options.
Now you should build the httpd executable by using the make
utility.
% make
This command prepares mod_perl extension files, installs them in the
Apache source tree and builds the httpd executable (the Web server
itself) by compiling all the required files. Upon completion of the
make
process, you get returned to the mod_perl source distribution
directory.
make test
executes various mod_perl tests on the freshly built
httpd executable.
% make test
This command starts the server on a nonstandard port (8529) and tests whether all parts of the built server function correctly. If something goes wrong, then the process will report it to you.
make install
completes the installation process of mod_perl by
installing all the Perl files required for mod_perl to run and, of
course, the server documentation (man pages).
% make install
You can use the following commands concatenation style:
% make && make test && make install
It simplifies the installation, since you don't have to wait for each command to complete before starting the next one. When installing mod_perl for the first time, it's better to do it step by step.
If you choose the all-in-one approach, then you should know that if make
fails, then neither make test
nor make install
will be executed. If
make test
fails, then make install
will not be executed.
Finally, change to the Apache source distribution directory, run make install to create the Apache directory tree and install Apache header files (*.h), default configuration files (*.conf), the httpd executable and a few other programs.
% cd ../apache_1.3.20
% make install
Note that, as with a plain Apache installation, any configuration files left from a previous installation won't be overwritten by this process. You don't need to back up your previously working configuration files before the installation.
When the make install
process completes, it will tell you how to
start a freshly built Web server (the path to the apachectl
utility
that is being used to control the server) and where the installed
configuration files are. Remember or, even better, write down both of
them, since you will need this information. On my machine
the two important paths are:
/usr/local/apache/bin/apachectl
/usr/local/apache/conf/httpd.conf
So far, we have completed the building and installation of the mod_perl enabled Apache. The next steps are to configure httpd.conf, write a little test script, start the server and check that the test script is working.
First things first; we want to make sure that our Apache was built correctly and that we can serve plain HTML files with it. Why do that? To minimize the number of possible trouble makers, if we find out that mod_perl doesn't work. After you know that Apache can serve HTML files, you don't have to worry about it anymore. And if something goes wrong with mod_perl, you have eliminated the possibility that the httpd binary or basic configurations are broken, you know that you are allowed to bind to the port you have configured your server to listen to, and that the browser you're testing with is just fine. Again, you should follow these guidelines when installing mod_perl for the first time.
Configure Apache as you always do. Set Port
, User
, Group
,
ErrorLog
and other directives in the httpd.conf file (remember
I've asked you to remember the location of this file at the end of the
previous section?). Use the defaults as suggested, customize only when
you have to. Values that you need to customize are ServerName
,
Port
, User
, Group
, ServerAdmin
, DocumentRoot
and a few
others. You will find helpful hints preceding each directive. Follow
them if in doubt.
When you have edited the configuration file, it's time to start the
server. One of the ways to start and stop the server is to use the
apachectl
utility. You start the server with:
% /usr/local/apache/bin/apachectl start
And stop it with:
% /usr/local/apache/bin/apachectl stop
Note that you have to be root when starting the server if the
server is going to listen on port 80
or another privileged port
(<1024).
After you start the server, check in the error_log file
(/usr/local/apache/logs/error_log is the file's default location)
that the server has indeed started. Don't rely on the status
apachectl
reports. You should see something like this:
[Thu Jun 22 17:14:07 2000] [notice] Apache/1.3.20 (Unix)
mod_perl/1.26 configured -- resuming normal operations
Now point your browser to http://localhost/ or
http://your.server.name/ as configured with the ServerName
directive. If you have set a Port
directive with a value different
from 80
, then apply this port number at the end of the server name. If
you have used port 8080, then test the server with
http://localhost:8080/ or http://your.server.name:8080/. You
should see the infamous ``It worked'' page, which is an index.html
file that make install
in the Apache source tree installs for you.
If you don't see this page, then something is wrong and you should check
the contents of the error_log file. You will find the path of the
error log file by looking it up in the ErrorLog
directive in
httpd.conf.
If everything works as expected, then shut down the server, open httpd.conf in your favorite editor, and scroll to the end of the file, where we will add the mod_perl configuration directives (of course you can place them anywhere in the file).
Assuming that you put all scripts that should be executed by the mod_perl enabled server in the /home/httpd/perl/ directory, add the following configuration directives:
Alias /perl/ /home/httpd/perl/
PerlModule Apache::Registry
<Location /perl>
SetHandler perl-script
PerlHandler Apache::Registry
Options ExecCGI
PerlSendHeader On
allow from all
</Location>
Save the modified file.
This configuration causes each URI starting with /perl to be
handled by the Apache mod_perl module. It will use the handler from
the Perl module Apache::Registry
.
Now create a /home/httpd/perl/ directory if it doesn't yet exist. In order for you and Apache to be able to read, write and execute files we have to set correct permissions. You could get away by simply doing:
% chmod 0777 /home/httpd/perl
This is very, very insecure and you should not follow this approach on the production machine. This is good enough when you just want to try things out and want to have as few obstacles as possible. Once you understand how things work, you should tighten the permissions of files served by Apache. In future articles, we will talk about setting proper file permissions.
As you probably know, mod_perl allows you to reuse CGI scripts written in Perl that were previously used under mod_cgi. Therefore, our first test script can be as simple as:
mod_perl_rules1.pl
------------------
print "Content-type: text/plain\r\n\r\n";
print "mod_perl rules!\n";
Save this script in the /home/httpd/perl/mod_perl_rules1.pl file. Notice that the shebang line is not needed with mod_perl, but you can keep it if you want. So the following script can be used as well:
mod_perl_rules1.pl
------------------
#!/usr/bin/perl
print "Content-type: text/plain\r\n\r\n";
print "mod_perl rules!\n";
Of course you can write the same script using the Apache Perl API:
mod_perl_rules2.pl
------------------
my $r = shift;
$r->send_http_header('text/plain');
$r->print("mod_perl rules!\n");
Save this script in the /home/httpd/perl/mod_perl_rules2.pl file.
Now make both of the scripts executable and readable by the server. Remember that when you execute scripts from a shell, they are being executed by the user-name you are logged with. When instead you try to run the scripts by issuing requests, Apache needs to be able to read and execute them. So we make the script readable and executable by everybody:
% chmod 0755 /home/httpd/perl/mod_perl_rules1.pl \
/home/httpd/perl/mod_perl_rules2.pl
If you don't want other users to be able to read your script, then you
should add yourself into the groupname the Web server is running with
(as defined by the Group
directive) and then make the script owned
by that group and tighten the permissions. For example, on
my machine I run the server under the group httpd and I'm the only
one who is in the same group, so I can do the following:
% chown stas.httpd /home/httpd/perl/mod_perl_rules1.pl \
/home/httpd/perl/mod_perl_rules2.pl
% chmod 0750 /home/httpd/perl/mod_perl_rules1.pl \
/home/httpd/perl/mod_perl_rules2.pl
The first command makes the files belong to group httpd, the second sets the proper execution and read permissions.
That's secure, assuming that you have a dedicated groupname for your server.
Also, remember that all the directories that lead to the script should be readable and executable by the server.
You can test mod_perl_rules1.pl from the command line, since it is essentially a regular Perl script.
% perl /home/httpd/perl/mod_perl_rules1.pl
You should see the following output:
mod_perl rules!
You cannot test the second script by executing it from the command line since it uses the mod_perl API that is available only when run from within the mod_perl server.
Make sure the server is running and issue these requests using your favorite browser:
http://localhost/perl/mod_perl_rules1.pl
http://localhost/perl/mod_perl_rules2.pl
In both cases you will see on the following response:
mod_perl rules!
If you see it--congratulations! You have a working mod_perl server.
If you're using port 8080 instead of 80, then you should use this number in the URL:
http://localhost:8080/perl/mod_perl_rules1.pl
http://localhost:8080/perl/mod_perl_rules2.pl
The localhost
approach will work only if the browser is running on
the same machine as the server. If not, then use the real server name for
this test. For example:
http://your.server.name/perl/mod_perl_rules1.pl
If there is any problem, then please refer to the error_log file for the error reports.
Now it's a time to move your CGI scripts from /somewhere/cgi-bin directory to /home/httpd/perl/ and see them running much much faster, when requested from the newly configured base URL (/perl/). If you were accessing the script as /cgi-bin/test.pl, then it will now be accessed from /perl/test.pl.
Some of your scripts might not work immediately and will require some minor tweaking or even a partial rewrite to work properly with mod_perl. Chances are that if you are not practicing sloppy programming, then the scripts will work without any modifications.
If you have a problem with your scripts, then a good approach is to replace
Apache::Registry
with Apache::PerlRun
in httpd.conf, as the
latter can execute really badly written scripts. Put the following
configuration directives instead in httpd.conf and restart the
server:
PerlModule Apache::PerlRun
<Location /perl>
SetHandler perl-script
PerlHandler Apache::PerlRun
Options ExecCGI
PerlSendHeader On
allow from all
</Location>
Now your scripts should work, unless there is something in them mod_perl doesn't accept. We will discuss these nuances in future articles.
mod_perl is about running both scripts and handlers. Although I have started to present mod_perl using scripts, because it's easier if you have written CGI scripts before, the more advanced use of mod_perl is about writing handlers. But have no fear. As you will see in a moment, writing handlers is almost as easy as writing scripts.
To create a mod_perl handler module, all I have to do is to wrap the
code I have used for the script into a handler
subroutine, add a
statement to return the status to the server when the subroutine has
successfully completed, and append a package declaration at the top of
the code.
Just as with scripts you can use either the CGI API you are probably used to:
ModPerl/Rules1.pm
----------------
package ModPerl::Rules1;
use Apache::Constants qw(:common);
sub handler{
print "Content-type: text/plain\r\n\r\n";
print "mod_perl rules!\n";
return OK;
}
1; # satisfy require()
or the Apache Perl API that allows you to interact more intimately with the Apache core by providing an API unavailable under regular Perl. Of course, in the simple example that I show, using any of the approaches is fine, but when you need to use the API, this version of the code should be used.
ModPerl/Rules2.pm
----------------
package ModPerl::Rules2;
use Apache::Constants qw(:common);
sub handler{
my $r = shift;
$r->send_http_header('text/plain');
print "mod_perl rules!\n";
return OK;
}
1; # satisfy require()
Create a directory called ModPerl under one of the directories in
@INC
(e.g. /usr/lib/perl5/site_perl/5.005), and put Rules1.pm
Rules2.pm into it, the files should include the code from the above
examples.
To find out what the @INC
directories are, execute:
% perl -le 'print join "\n", @INC'
On my machine it reports:
/usr/lib/perl5/5.6.1/i386-linux
/usr/lib/perl5/5.6.1
/usr/lib/perl5/site_perl/5.6.1/i386-linux
/usr/lib/perl5/site_perl/5.6.1
/usr/lib/perl5/site_perl
.
Now add the following snippet to httpd.conf to configure mod_perl
to execute the ModPerl::Rules::handler
subroutine whenever a
request to mod_perl_rules1 is made:
PerlModule ModPerl::Rules1
<Location /mod_perl_rules1>
SetHandler perl-script
PerlHandler ModPerl::Rules1
</Location>
Now you can issue a request to:
http://localhost/mod_perl_rules1
and just as with our mod_perl_rules.pl scripts you will see:
mod_perl rules!
as the response.
To test the second module <ModPerl::Rules2> add the same configuration, while replacing all 1's with 2's:
PerlModule ModPerl::Rules2
<Location /mod_perl_rules2>
SetHandler perl-script
PerlHandler ModPerl::Rules2
</Location>
And to test use the URI:
http://localhost/mod_perl_rules2
Obviously, the next question you'll ask is: ``Is this all I need to know about mod_perl?''.
The answer is: `yes and no.
The yes part:
The No part:
Of course, when you test a single script and you are the only user, you don't really care about squeezing yet another millisecond from response time, but it becomes a real issue when these milliseconds add up at the production site, with hundreds of users concurrently generating requests to various scripts on your site. Users aren't merciful nowadays -- if there is another even less fancier site that provides the same service but a little bit faster, then chances are that they will go over there.
Testing your scripts on an unloaded machine can be misleading, Everything might seem so perfect. But when you move them into a production machine, things don't behave as well as they did on your development box. Many times you just run out of memory on busy services. You need to learn how to optimize your code to use less memory and how to make the memory shared.
Debugging is something people prefer not to talk about, since the process can be tedious. Learning how to make the debugging process simpler and efficient is a must if you consider yourself a Web programmer. This task is especially not so straightforward when debugging CGI scripts, and even more complicated with mod_perl -- unless you know how, and then it suddenly becomes easy.
mod_perl has many features unavailable under mod_cgi when working with databases. Among others the most important are persistent connections.
You have to know how to keep your service running nonstop and be able to recover fast if there are any problems.
Finally, the most important thing is the Apache-Perl API, which allows you to do anything with a received request, even intervene in every stage of request processing. This gives you great flexibility and allows you to create things you couldn't dream about with plain mod_cgi.
There are many more things to learn about mod_perl and Web programming in general. In future articles, I'll talk in details about all these issues.
Many thanks to Eric Cholet for reviewing this article.
Return to Related Articles from the O'Reilly Network .
Perl.com Compilation Copyright © 1998-2003 O'Reilly & Associates, Inc.