I use Apache as the base. With Apache, I compile in mod_ssl for HTTPS and mod_perl for dynamic serving.

If you happen to use FreeBSD, you can use my port of this combo.

For a database backend, I use PostgreSQL and its associated Perl modules (DBI, DBD::Pg).

Additionally, HTML::Mason comes to the rescue in creating dynamic pages. It provides a nice way of mixing HTML and Perl.


Install Apache::Session from CPAN.

After that is done, you'll need to create a database table for the sessions. This is a little different than the default specified in Apache::Session::DBIStore.

create table sessions ( id char(16), length int4, a_session text );
Also, you will need this patch against Apache::Session::DBIStore to freeze and thaw the values since PostgreSQL isn't as friendly to binary values.

Now create a handler.pl:

package HTML::Mason;
use HTML::Mason;    # brings in subpackages: Parser, Interp, etc.
use strict;

$Apache::Session::DBIStore::DataSource       = 'dbi:Pg:dbname=DATABASE';
$Apache::Session::DBIStore::UserName         = 'USER';
$Apache::Session::SysVSemaphoreLocker::nsems = 16;

use HTML::Mason::Commands;    # brings in subpackages: Parser, Interp, etc.
use Apache::Cookie;
use Apache::Session::DBI;

my $parser = new HTML::Mason::Parser;
my $interp = new HTML::Mason::Interp (parser=>$parser,
my $ah = new HTML::Mason::ApacheHandler (interp=>$interp);
chown ( [getpwnam('nobody')]->[2], [getgrnam('nobody')]->[2],
        $interp->files_written );   # chown nobody

sub handler {
  my ($r) = @_;

  # don't serve up non-text files.
  return -1 if $r->content_type 
    && substr(lc $r->content_type, 0, 5) ne "text/";

  my %cookie = Apache::Cookie->fetch;

  eval {
    tie %session, 'Apache::Session::DBI',
        (defined $cookie{SID} ? $cookie{SID}->value : undef);
    if(not defined $cookie{SID}) {
      $cookie{SID} = Apache::Cookie->new($r,
                                         -name => "SID",
                                         -value => $session{_session_id},
                                         -path => "/");

  if(not defined $session{_session_id} || $@) {
    warn $@;
    tie %session, 'Apache::Session::DBI', undef;

  $session{lastaccess} = time;
  my $status = $ah->handle_request($r);

  untie %session;

  return $status;



Get HTTPD-User-Manage, which contains my modifications to interface with Apache::AuthCookie.

Alter the create_tables file in the distribution and feed it to postgresql to make the changes you need.


Install Apache::AuthCookie from CPAN and then add these lines to your apache.conf:

  SetHandler perl-script
  PerlHandler HTML::Mason
  PerlModule HTTPD::AuthCookieDBI

  Apache::DBI->connect_on_init("dbi:Pg:dbname=DBNAME", "USER")
  DefaultType text/html
  <Location /perl-status>
    SetHandler perl-script
    PerlHandler Apache::Status

  # For HTTPD::AuthCookie
  PerlSetVar FMLinkPath /
  PerlSetVar FMLinkLoginScript /login
  PerlSetVar FMLinkDomain .slideshow.org

  # These areas require login
  <Location /form>
    AuthType user
    AuthName FMLink
    PerlAuthenHandler HTTPD::AuthCookieDBI->authenticate
    PerlAuthzHandler HTTPD::AuthCookieDBI->authorize
    require valid-user

  <Location /admin>
    AuthType user
    AuthName FMLink
    PerlAuthenHandler HTTPD::AuthCookieDBI->authenticate
    PerlAuthzHandler HTTPD::AuthCookieDBI->authorize
    require group admin

  <Files LOGIN>
    AuthType user
    AuthName FMLink
    SetHandler perl-script
    PerlHandler HTTPD::AuthCookieDBI->login