HOWTO : nginx, Starman / Plack and Catalyst

In this short tutorial, I will demonstrate how to use nginx as a frontend web proxy and Starman as a backend web server running a Catalyst application.

It assumes you already know about PSGI, Catalyst, nginx and how to install all the required libraries and perl modules.

Requirements :

First, we’ll configure nginx to run as our lightweight http server.  (If you require SSL, please make sure your ./configure command includes the –with-http_ssl_module option and that you have the openssl and pcre libraries already installed)

I’m going to require a ssl connection with a self signed certificate (you can follow the instructions here on how to set that up). I will also be redirecting all http requests to https via the web server (which is the best way to handle this).

In your nginx directory (mine was installed at /usr/local/nginx) edit your conf/nginx.conf file :

... (params)
http {
... (params, default server, etc)
  server {
    listen 80;
    server_name   myapp.example.com;
    location / {
      rewrite         ^/(.*)$ https://myapp.example.com/$1 permanent;
    }
  }

  server {
    listen        443 ssl;
    server_name   myapp.example.com;
    gzip on;
    ssl_certificate /usr/local/nginx/conf/server.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
    #you may need or want to set additional ssl parameters (cipher, etc)

    location / {
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Port 443; #this is important for Catalyst Apps!
      proxy_pass http://localhost:5000; #changed from http://localhost:5000/ which was causing double forward slash problems in the url
    }

  location /static {
    root /data/users/MyApp/root;
    expires 30d;
  }
}

This assumes that your static content will be servered by nginx and not your Catalyst App, and that when you start your starman server, you’ll be using port 5000.

To get your Catalyst up and running using Starman, install the Plack and Starman via cpanminus as well as the Catalyst::Engine::PSGI module for PSGI integration. Once all of your modules are installed, you’ll need to create a app.psgi file.  You can do so manually, or via the script/app_create.pl command in your Catalyst App directory.

As I found out here from my own answer, when using a front-end web proxy, you’ll need to add a small bit of information to your .psgi file (Catalyst::Engine::PSGI docs), here’s an example of mine :

#!/usr/bin/env perl
use strict;
use warnings;

use Plack::Builder;
use MyApp;

MyApp->setup_engine('PSGI');
my $app = sub { MyApp->run(@_) };

builder {
 enable_if { $_[0]->{REMOTE_ADDR} eq '127.0.0.1' }
        "Plack::Middleware::ReverseProxy";
 $app;
};

If your instance of nginx is running on a different server, you may need to set this configuration variable in your Catalyst App (doesn’t hurt to add it regardless of your situation) :

MyApp->config(using_frontend_proxy => 1)

Start starman (currently defaults to 5 processes and port 5000) :
$ starman script/erp.psgi

Start nginx
$ sudo /usr/local/nginx/sbin/nginx

At this point, all of your http://myapp.example.com requests should be automatically redirected to https://myapp.examples.com. Nginx should be handling all of your static content used by your Catalyst app, and as long as Starman is running in the background on port 5000, your requests and responses should be handled accordingly and in a timely manner! ;-)

In a production production environment, you may want to tweak some of your settings in the nginx.conf file and then create a startup script for both nginx and your Starman server. I also haven’t touched on any of the logs associated with Starman / Plack and your Catalyst app, or how to handle the ip addresses (nginx if forwarding the $remote_addr as `X-Real-IP` in the header) for access / error logs…

  1. Would you explain the advantages or even purpose of this set up? Do you have some benchmarks to show what kind of speed up this produces over a plain vanilla apache 2 with CGI set up?

  2. Thanks for sharing this. I’m not using Catalyst, but another Plack application pairing nginx and Starman and your example was very helpful.