mod_perl in 30 minutes
by Stas Bekman
|
Pages: 1, 2
Configuring and Starting mod_perl Server
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.
Preparing the Scripts Directory
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.
The ``mod_perl rules'' Apache::Registry Script
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.
The ``mod_perl rules'' Apache Perl Module
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
Is This All I Need to Know About mod_perl?
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:
- Just like with Perl, you have to know little about mod_perl to do really cool stuff. The presented setup allows you to run your visitor counters and guest book much faster, and amaze your friends, usually without changing a single line of code.
The No part:
-
A 50-fold improvement in guest book response times is great, but when
you deploy a heavy service with thousands of concurrent users,
taking into account a high-level competition between similar Web
services, a delay of a few milliseconds might cost you a customer and
probably many of them.
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.
References
The Apache site's URL: http://www.apache.org/
The mod_perl site's URL: http://perl.apache.org/
CPAN is the Comprehensive Perl Archive Network. The Master site's URL is http://cpan.org/. CPAN is mirrored at more than 100 sites worldwide. (http://cpan.org/SITES.html)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.
Acknowledgements
Many thanks to Eric Cholet for reviewing this article.

