Question

I've been doing web-programming for a while now and am quite familiar with the LAMP stack. I've decided to try playing around with the nginx/starman/dancer stack and I'm a bit confused about how to understand, from a high-level, how all the pieces relate to each other. Setting up the stack doesn't seem as straight forward as setting up the LAMP stack, but that's probably because I don't really understand how the pieces relate.

I understand the role nginx is playing - a lightweight webserver/proxy - but I'm confused about how starman relates to pgsi, plack and dancer.

I would appreciate a high-level breakdown of how these pieces relate to each other and why each is necessary (or not necessary) to get the stack setup. Thanks!

Was it helpful?

Solution

I've spent the last day reading about the various components and I think I have enough of an understanding to answer my own question. Most of my answer can be found in various places on the web, but hopefully there will be some value to putting all the pieces in one place:

  • Nginx: The first and most obvious piece of the stack to understand is nginx. Nginx is a lightweight webserver that can act as a replacement for the ubiquitous Apache webserver. Nginx can also act as a proxy server. It has been growing rapidly in its use and currently serves about 10% of all web domains. One crucial advantage of nginx is that it is asynchronous and event-driven instead of creating a process thread to handle each connection. In theory this means that nginx is able to handle a large number of connections without using a lot of system resources.
  • PSGI: PSGI is a protocol (to distinguish it from a particular implementation of the protocol, such as Plack). The main motivation for creating PSGI, as far as I can gather, is that when Apache was first created there was no native support for handling requests with scripts written in e.g., Perl. The ability to do this was tacked on to Apache using mod_cgi. To test your Perl application, you would have to run the entire webserver, as the application ran within the webserver. In contrast, PSGI provides a protocol with which a webserver can communicate with a server written in e.g. Perl. One of the benefits of this is that it's much easier to test the Perl server independently of the webserver. Another benefit is that once an application server is built, it's very easy to switch in different PSGI-compatible webservers to test which provides the best performance.
  • Plack: This is a particular implementation of the PSGI protocol that provides the glue between a PSGI-compatible webserver and a perl application server. Plack is Perl's equivalent of Ruby's Rack.
  • Starman: A perl based webserver that is compatible with the PSGI protocol. One confusion I had was why I would want to use both Starman and Nginx at the same time, but thankfully that question was answered quite well here on Stackoverflow. The essence is that it might be better to let nginx serve static files without requiring a perl process to do that, while also allowing the perl application server to run on a higher port.
  • Dancer: A web application framework for Perl. Kind of an equivalent of Ruby on Rails. Or to be more precise, an equivalent of Sinatra for Ruby (the difference is that Sinatra is a minimalist framework, whereas Ruby on Rails is a more comprehensive web framework). As someone who dealt with PHP and hadn't really used a web framework before, I was a bit confused about how this related to the serving stack. The point of web frameworks is they abstract away common tasks that are very frequently performed in web applications, such as converting database queries into objects/data structures in the web application.

  • Installation (on ubuntu):

    sudo apt-get install nginx
    sudo apt-get install build-essential curl
    sudo cpan App::cpanminus
    sudo cpanm Starman
    sudo cpanm Task::Plack
    sudo apt-get install libdancer-perl
  • Getting it running:
cd
dancer -a mywebapp
sudo plackup -s Starman -p 5001 -E deployment --workers=10 -a mywebapp/bin/app.pl

Now you will have a starman server running your Dancer application on port 5001. To make nginx send traffic to the server you have to modify

/etc/nginx/nginx.conf
and add a rule something like this to the http section:

        server {
               server_name permanentinvesting.com
               listen 80;

                location /css/ {
                  alias /home/ubuntu/mywebapp/public/css/;
                  expires 30d;
                  access_log off;
                }



               location / {
                  proxy_pass        http://localhost:5001;
                  proxy_set_header  X-Real-IP  $remote_addr;
                }

        }

The first location rule specifies that nginx should handle static content in the /css directory by getting it from

/home/ubuntu/mywebapp/public/css/
. The second location rule says that traffic to the webserver on port 80 should be sent to the Starman server to handle. Now we just need to start nginx:

sudo service nginx start

OTHER TIPS

Your Answer is so far correct, but it would be better to set up nginx the following way:

server {
    listen 80;
    server_name foo.example.com;

    location / {
        # Serve static files directly:
        if (-f $request_filename) {
            expires 30d;
            break;
        }

        # Pass on other requests to Dancer app
        proxy_pass_header Server;
        proxy_pass http://localhost:5001/;
    }
}

This make nginx serve all static files (JavaScript and images) and not just the css.

This example is taken from the 2011 Perl Dancer Advent :)

From nginx wiki:
"IfIsEvil ... Directive if has problems when used in location context, in some cases it doesn't do what you expect but something completely different instead. In some cases it even segfaults. It's generally a good idea to avoid it if possible...."

A better set up is:

server {
    listen 80;
    server_name foo.example.com;

    location / {  
    # Checks the existence of files and uses the first match
                try_files $uri $uri/ @dancer;
          } 

    location @dancer {
    # Pass on other requests to Dancer app
            proxy_pass_header Server;
            proxy_pass http://localhost:5001/;
        }
}

Correction for the answer from s.magri:

location @dancer {
  # Pass on other requests to Dancer app
  proxy_pass_header Server;
  proxy_pass http://localhost:5001;
}

I had to remove the trailing slash in the last proxy_pass directive. My version of nginx (1.10.3) won't start up with the trailing slash.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top