How to get a PSGI app running with mod_fastcgi on Ubuntu with Apache2

First make sure you activate the multiverse repository for apt.

Then install the required modules (if you don't already have them enabled)

sudo aptitude install libapache2-mod-fastcgi apache2-suexec

Enable the fastcgi and rewrite modules:

sudo a2enmod fastcgi
sudo a2enmod rewrite

Edit /etc/apache2/mods-enabled/fastcgi.conf and enable the FastCgiWrapper so that the .fcgi script is run as the owner of the script. This is why apache2-suexec above is needed.

Then add the following to the file if you like to be able to just touch the psgi.fcgi file to get it to reload your app.

FastCgiConfig -autoUpdate

My /etc/apache2/mods-enabled/fastcgi.conf is like this:

<IfModule mod_fastcgi.c>
  AddHandler fastcgi-script .fcgi
  FastCgiWrapper /usr/lib/apache2/suexec
  FastCgiIpcDir /var/lib/apache2/fastcgi
  FastCgiConfig -autoUpdate

Then you need a small wrapper script to actually run your PSGI app. I call it psgi.fcgi:

use strict;
use warnings;
# For CPAN modules in your home-dir (see local::lib)
use lib "/home/robin/perl5/lib/perl5";
use lib "/home/robin/perl5/lib/perl5/i486-linux-gnu-thread-multi";
use Plack::Server::FCGI;
Plack::Server::FCGI->new->run(do "app.psgi");

The use lib statements are there because I use local::lib. I just grabbed them from the PERL5LIB environment variable. If someone has a better solution on how to write this wrapper with support for local::lib, I'd like to hear it.

The next thing is to add a nice .htaccess file so that you can make flexible apps that use PATH_INFO and other nice things (this is where mod_rewrite comes in).

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ psgi.fcgi/$1 [QSA,L]

Change this one if you'd like Apache to handle static files by itself instead of forwarding the requests to your application.

Finally I just made a small app.psgi that prints the environment as you try out different paths below your base folder. Pay close attention to how PATH_INFO changes as you try it out.


use strict;
use warnings;

sub {
    my ($env) = @_;
    my @out = ( "Your \$env hash:\n\n" );
    foreach my $key ( sort keys %{ $env } ) {
        push @out, $key, ' = ', $env->{$key}, "\n";
    return [
        [ 'Content-Type' => 'text/plain' ],

I'm using Plack 0.9006 from CPAN for this little experiment.

I think this will be my quick-and-easy way to deploy PSGI apps from now on.

Update: It seems the suexec wrapper doesn't do its job properly. The FastCGI script, psgi.fcgi, is apparently still running as www-data(33). If you know how to fix this problem please shout out in the comments.