Once you have your application working on the production machine, you're ready to point a real web server at it. Which server you use is usually decided by what your other applications are using. If you already have Apache and mod_perl set up, then use that. If you aren't serving many users, you will probably be fine with just the development server included with Catalyst. If you're tired of Apache, you can use lighttpd with FastCGI. Catalyst tries to make mod_perl, FastCGI, and the development server behave the same, so you should use whatever is convenient for you. (Note that plain CGI is also an option, but it will be unbearably slow, so don't use it.)
Generally, new deployments use Apache and FastCGI, as that configuration is relatively easy to set up and manage. As of writing, this FastCGI is the preferred configuration and unless you have reasons otherwise, you probably should just stick with FastCGI. mod_perl is most useful if you want to write an Apache module integrating Perl code directly into the web server. For applications, FastCGI is simpler to set up and manage in the usual cases.
Apache is the world's most common web server, so most sites are already using Apache and have a configuration that you can easily add to your Catalyst application. If you decide to use Apache, you can use either mod_perl or FastCGI to actually run your Catalyst application.
FastCGI is easiest of the two to set up; simply install mod_fastcgi (or the newer mod_fcgid, which might be better for some users) and add the following to Apache's httpd.conf
file:
FastCgiServer /.../myapp/script/myapp_fastcgi.pl -processes 3 Alias /myapp/ /.../myapp/script/myapp_fastcgi.pl/
Please note that in the last lines of code, the ellipsis (...) is an abbreviation for wherever you want your application code to live. Many sites use /var/www
or /var/www-apps
, but /home/myapp/
or something similar is also possible.
The Apache configuration may look like the following on a virtual host:
<VirtualHost *:80> AddHandler fastcgi-script .fcgi ServerName myapp.com ServerAlias www.myapp.com DocumentRoot /mnt/volume/www/myapp/root FastCgiServer /mnt/volume/www/myapp/script/myapp_fastcgi.pl - processes 1 Alias /static/ /mnt/volume/www/myapp/root/static/ Alias / /mnt/volume/www/myapp/script/myapp_fastcgi.pl/ <Location /mnt/volume/www/myapp/root/static/> SetHandler default-handler </Location> </VirtualHost>
For more details on setting up fastcgi on Apache, you can read http://httpd.apache.org/mod_fcgid/.
This configuration will tell Apache to start (and maintain) three instances of your application, and to make the application available on the web under the /myapp
URL. You can put the Alias
directive inside a VirtualHost
block to make your application available at the root of a virtual host.
If you'd like to run your FastCGI server on a separate machine, you can tell Apache about a FastCGI external server:
FastCgiExternalServer /var/www/htdocs/myapp.fcgi -host remote.server. com:3010 Alias /myapp/ /var/www/htdocs/myapp.fcgi
Note that /var/www/htdocs/myapp.fcgi
isn't a real file; it's a virtual file that ends with .fcgi
(so Apache knows to invoke the fastcgi-handler) and exists inside the doc root (so Apache knows it's allowed to be served). The -host
directive points FastCGI at the server running on remote.server.com
, port 3010.
On remote.server.com
, you'll want to run scripts/myapp_fastcgi.pl -l :3010
and set up firewall rules so that only your frontend server can talk to port 3010. You can also use another port number, as there is no defined standard port.
If your application is in a PAR, you can start an external FastCGI server by running parl myapp.par myapp_fastcgi.pl -l :3010
. You can then configure a remote Apache with FastCGI to support to connect to that server, just as described above for the non-PAR case.
In addition, the external server need not be on another host, it can be run on localhost the same way. You can also use a named socket on the filesystem instead of a host and port; just say -socket
instead of -host
. It is easier to enforce permissions on files than TCP ports, so if you care about fine-grained access to the FastCGI server, then you might like using the named socket better. Keep in mind that you can't use a named socket when the FastCGI server is running on a different host from the frontend web server.
One last tweak is to have Apache serve your static content without involving your Catalyst application. All you'll need to do is add an Alias
directive like the following:
Alias /myapp/static /.../myapp/root/static
Apache can serve static content much more efficiently than your Catalyst application, so for maximum performance it's best to add this piece of configuration.
For years, mod_perl was the only way to write efficient web applications, so it's still in wide use. Serving your Catalyst application with mod_perl is very easy. First, you'll need Catalyst::Engine::Apache
from the CPAN.
Then, to a mod_perl-enabled Apache 2.x.x configuration, you'll just need to add the following lines:
PerlSwitches -I/.../myapp/lib PerlModule MyApp <Location /> # or you can use /myapp, or a VirtualHost, etc. SetHandler modperl PerlResponseHandler MyApp </Location>
On Apache 1.3, the setup is slightly different:
<Perl> use lib qw(/.../myapp/lib); </Perl> PerlModule MyApp <Location /> SetHandler perl-script PerlHandler MyApp </Location>
Finally, if you're using PAR, you can install Apache::PAR
and point Apache at the PAR instead of a directory:
PerlAddVar PARInclude /.../myapp.par PerlModule Apache::PAR PerlModule MyApp
These directives replace the<Perl>
or PerlSwitches
sections (but not the<Location>
section).
After you have set up your configuration, you can restart Apache and enjoy your application. The same static caveat with FastCGI applies to mod_perl, so you will want to add an alias or location for serving the static content directly. (This is more difficult with PAR, but you might want to take the slight performance hit for the convenience of one-file deployment. Additionally, you can copy the static content somewhere outside of the PAR file and use only the PAR for code. Then there is no performance hit, but maintenance is slightly more difficult.)
Unfortunately, the mod_perl setup described in the previous section is not ideal. mod_perl works by loading your entire application into every Apache process. This means that when an Apache process has to spoon-feed a dial-up user a 200M movie (or 20k of HTML, the concept is the same), the memory that your application used is wasted streaming bytes instead of processing requests. On sites with high traffic, this will result in unacceptable performance, as the application processes will be tied up serving data (and you can't start more application processes because you'll be out of memory).
This is a well-known mod_perl problem not specific to Catalyst (or even Perl, mod_ruby, and mod_python suffer the same problem), and is part of the reason why FastCGI is becoming popular.
The solution is to run a two-tiered architecture. In front of your mod_perl application processes, you place a lean load balancer (such as perlbal) or a basic Apache process. The frontend will pass dynamic requests to the backend application servers. When the dynamic result is ready, the dynamic server will send it very quickly to the frontend server. The frontend server will then send the response to the client. While that frontend server is tied up, another lean frontend server can dispatch another dynamic request to your application. This setup ensures that you are always using as much CPU and bandwidth as possible.
Setting up a frontend server is covered in the mod_perl book at http://perl.apache.org/, and perlbal is covered in the next section. The only thing you need to do for Catalyst is to tell it that there's a frontend proxy by setting using_frontend_proxy
to 1
in the application config. This option is necessary so that Catalyst will generate URLs that point to the frontend server when you use uri_for
and uri_for_action
.
If you're going to use mod_perl for a large site, be sure to set up a two-tiered architecture.
The final deployment option is to simply use the myapp_server.pl
development server. This server is not intrinsically limited in any way; you can expose it to the Internet and your application will work fine. The main problem is the same as mod_perl, though; feeding the resulting HTML (or images, and so on) back to the client will tie up system memory unnecessarily. Additionally, as the development server can handle only one connection at a time, users will have to wait in line to use your application, which is probably not acceptable unless you are creating something like a desktop web application.
That means it's easy to get a very efficient two-tiered setup going with perlbal. The basic idea is to start a pool of development servers running on different ports, and then have perlbal load balance between them. perlbal will handle talking to clients and will send dynamic requests to a waiting development server. The performance of this setup will be excellent, as perlbal adds almost no overhead (it's used for popular sites such LiveJournal and Vox, and easily handles hundreds of millions of requests a day).
To get started, install perlbal from the CPAN (it's also available at http://www.danga.com/perlbal/). Then, create a simple perlbal configuration file called /etc/perlbal/perlbal.conf
that looks like this:
CREATE POOL myapp POOL myapp ADD 127.0.0.1:3010 POOL myapp ADD 127.0.0.1:3011 POOL myapp ADD 127.0.0.1:3012 POOL myapp ADD 127.0.0.1:3013 CREATE SERVICE balancer SET listen = 0.0.0.0:80 SET role = reverse_proxy SET pool = myapp SET persist_client = on SET persist_backend = on ENABLE balancer # open up a management port for dynamic configuration CREATE SERVICE mgmt SET role = management SET listen = 127.0.0.1:60000 ENABLE mgmt
When that's set up, start a few instances of your application:
$ perl script/myapp_server.pl -p 3010 -d
$ perl script/myapp_server.pl -p 3011 -d
$ perl script/myapp_server.pl -p 3012 -d
$ perl script/myapp_server.pl -p 3013 -d
and start perlbal:
$ perlbal
Now visit http://localhost/
, and you should be good to go. If you choose to keep perlbal's management interface up, you should firewall off its port (60000).
Storage and schema deployment, upgrade, and maintenance could be a major challenge if not handled with care. You may want to explore the class DBIx::Class::Schema::Versioned
that helps with schema versioning. Refer to
http://search.cpan.org/~ash/DBIx-Class-0.08013/lib/DBIx/Class/Schema/Versioned.pm.
18.226.251.206