Mounting Apps with Plack
Plack has the ability to map applications onto URLs. This is facilitated with Plack::App::URLMap. Here I will demonstrate how one can use Plack and URLMap to mount multiple applications. In addition, we examine how to handle static file requests and requests to “/”.
Table of Contents
Load the application library paths
I have three Catalyst applications and one Web::Simple application that I’d like to load. Here I make sure their modules are in @INC.
use strictures 1; use lib '/home/user/apps/mojomojo/lib'; use lib '/home/user/apps/Bracket/lib'; use lib '/home/user/apps/HomePage/lib'; use lib '/home/user/apps/Mojito/lib';
Load some Plack modules
Plack::Builder provides us with a Domain Specific Language (DSL) to easily manage multi-app URL mounting while Plack::Util allows us to load a Plack application from a file. Further, Plack::App::File is used to load static files (e.g. /css/*). Finally, Plack::App::Cascade is used to allow two applications to handle requests to “/*”.
use Plack::Builder; use Plack::Util; use Plack::App::File; use Plack::App::Cascade;
Create PSGI apps from Catalyst apps
Three of the applications we want to load and mount are Catalyst based. The approach is to get a PSGI application that we’ll point a URL at. Here’s how we get a PSGI Catalyst application:
use MojoMojo; MojoMojo->setup_engine('PSGI'); my $mojomojo_app = sub { MojoMojo->run(@_) }; use Bracket; Bracket->setup_engine('PSGI'); my $bracket_app = sub { Bracket->run(@_) }; use HomePage; HomePage->setup_engine('PSGI'); my $homepage_app = sub { HomePage->run(@_) };
Load a PSGI app from a file
I have a fourth application that I would like to mount. I use load_psgi in this example to load a Web::Simple psgi application from a file1.
my $mojito_app = Plack::Util::load_psgi '/home/user/apps/Mojito/app/mojito.pl';
Using Plack::App::File and Cascade
I’d like to be able be able to serve static files as well as a “root” page for the domain. Here I use Plack::App::File to create a static file server application, and I embed a very simple app which will handle the requests to “/”. Both apps are then cascaded together into $cascaded_root_app with $static_app getting the first shot at responding followed by $root_app
my $static_app = Plack::App::File->new(root => "/home/user/www"); my $root_app = sub { [200, ['Content-type', 'text/html'],['Hola els meus amics.']] }; my $cascaded_root_app = Plack::App::Cascade->new(apps => [$static_app, $root_app ])->to_app;
Mapping apps to URLs
OK so we have a few PSGI apps now that we can mount. Here’s how it’s done:
builder {
mount "/wiki" => builder {
enable_if { $_[0]->{REMOTE_ADDR} eq '127.0.0.1' }
"Plack::Middleware::ReverseProxy";
$mojomojo_app;
};
mount "/bracket" => builder {
enable_if { $_[0]->{REMOTE_ADDR} eq '127.0.0.1' }
"Plack::Middleware::ReverseProxy";
$bracket_app;
};
mount "/homie" => $homepage_app;
mount "/note" => $mojito_app;
mount "/" => $cascaded_root_app;
};
So we’ve mounted 4 applications to four different /${mount_points} and we’ve setup the root of the server to handle static requests. In addition, a request for “/” will be handled by the $root_app we have cascaded with the $static_app.
Furthermore, one may notice the use of Plack::Middleware::ReverseProxy for a couple of the Catalyst apps. This allows us to proxy to these applications from something like nginx and have valid internal URLs.
Nginx Deployment
So now that we have a PSGI multi-mounted application, let’s call it my_web_apps.psgi we can start it up with plackup like so:
plackup -s Starman my_web_apps.psgi
This will start and mount on the applications on the default port of 5000 using the Starman backend. If I’d like to have an nginx front-end proxy to this multi-app I can configure /etc/nginx/sites-enabled/default something like:
upstream webapps_backend_url {
server 127.0.0.1:5000;
}
...
server {
...
location / {
proxy_pass http://webapps_backend_url;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $http_host;
}
...
}
Closing
In summary, one can see the flexibility of the Plack family of modules to mount multiple applications and even cascade them. Once a person has a multi-app psgi file they can choose whatever backend server they like to run it against, Starman in this example. In addition, nginx makes it easy to reverse-proxy to the applications with a few configuration lines. Lastly one could control the start/stop of the applications with an init.d script. See jshirley’s example for starters.
Foot Notes
1 The use of load_psgi could be employed with the Catalyst apps as well.
References
Showing changes from previous revision. Removed | Added
