Here we create an absolutely minimal multi-tenant webserver,
without even installing Apache or NginX. Although we can add either of
those later, with our content running under them as reverse proxies,
this tutorial lets you run one or more Mojolicious "apps" mounted under
a single toadfarm startup script, saving you the "default perl memory"
times the number of worker processes and apps.
We will b using Jan Henning Thorsen's Toadfarm:
Toadfarm is a module for configuring and starting your Mojolicious
applications. You can either combine multiple applications in one
script, or just use it as a init script.
First, perform a Debian Netinstall on a
virtual machine or virtual host. The only modification to all the
default selections is to enable only "Standard System Utilities" and
disable desktop, database, mail, print, file, and web server. We will
be building our own of all those!
Now boot up into that absolutely stock, base machine. For illustration,
we will assume your username is gronk
− change this as necessary.
First let's install a few system packages (ssh for access; curl for
installing Perlbrew et al; sudo for convenience;
build-essential for GCC, Make, and the compiler tools; and the no-X
version of emacs because I've
been using it since 1980):
$ su
# apt-get install sudo ssh curl build-essential emacs-nox
# usermod -a -G sudo <em>gronk</em> # exit
Now we install our Perlbrew environment as the user:
$ \curl -L http://install.perlbrew.pl | bash
$ echo source ~/perl5/perlbrew/etc/bashrc >> ~/.bash_profile
$ perlbrew install 5.22.0 -j5
The -j5 means use five processes for the Make. Then:
$ perlbrew switch 5.22.0
$ perlbrew install-cpanm
$ curl -L https://cpanmin.us | perl - -M https://cpan.metacpan.org -n Mojolicious
$ cpanm Toadfarm
jhthorsen explains how this goes together:
You can't run individual apps inside toadfarm as different user,
but you can start toadfarm as root and change to a different user.
[
This is true of Mojolicious generally
](https://metacpan.org/pod/Mojo::Server#user)
.
In particular, we create an Init script with a #! (hashbang) that
points to our user's "brewed" Perl. From the documentation:
Remember that the hashbang can be anything, so if you have Toadfarm
and Mojolicious running under
[
plenv
](https://github.com/tokuhirom/plenv)
or
Perlbrew
you need to change the hashbang part…
So we change our Init script to start with:
#!/home/<em>gronk</em>/perl5/perlbrew/perls/perl-5.22.0/bin/perl
Then in the Toadfarm script called by the Init script, which is started
as root, we do the switch to our user (called some-www-user in the
documentation, gronk here):
#/usr/bin/env perl
use Toadfarm -init;
# …
start [qw( http://*:80 https://*:443 )], user => "<em>gronk</em>", group => "<em>www</em>";
From the documentation:
Changing user has one implication: The workers will not use some-www-user's
secondary groups. So if "some-www-user" is part of the "www" and
"db" groups, then the process will only be run as "some-www-user"
part of the "www" group.
See also the IRC log for 26 April 2014.
We are experiencing Perl's most successful period since the 1990s.
I-Programmer spoke with Sebastian Riedel, originator of the relatively
new Mojolicious system built on Perl.
…The truth is that installing Mojolicious is simply a very fast
and pleasant experience… we've done with tight integration of WebSockets
and event loops, [and] the ability to grow from single-file prototypes
to well structured web applications.
The first example application you encounter on
[
our website
](http://mojolicio.us)
… doesn't look very complicated at all. But once you start digging
a little deeper, you'll quickly realize how crazy (in a good way)
it really is, and how hard it would be to replicate with any other
web framework, in any language…
Read the rest of the story
at i-programmer, 11 December 2014.
Module::Pluggable
is an under-appreciated way to write extensible programs. It has been
in the Perl core modules since Perl 5.8. [1] The author maintains a
Github repository.
use Module::Pluggable instantiate => function_name;
Instantiates an object for each pluggable module by calling the named
function (method); often you will want to pass "new". Or you might just
want to load (require) the modules, and not instantiate them:
use Module::Pluggable require => 1;
The return value to plugins() will then change from a list of the
installed module names, to a list of all the objects created. Note that
the change in return-value is undocumented. See also the option, on_instantiate_error
which controls what happens when things go wrong.
Module::Pluggable does expect the following protocol:
use Module::Pluggable search_path => "Plugins", instantiate => 'new';
searches the subdirectory ./Plugins for files named *.pm (although you
can change this with the file_regex parameter). For example, if you are writing a
Mojolicious model that should have pluggable submodules, you could do this:
# in lib/MyApp/Model/MyGeneralModel.pm
use Module::Pluggable require => 1, search_path => __PACKAGE__;
which would load all files matching lib/MyApp/Model/MyGeneralModel/*.pm
Each file, for example Plugins/plug1.pm
in the first example above,
is expected to contain a co-ordinating definition properly placed in
the object namespace hierarchy by matching the filename:
package Plugins::plug1;
sub new {
my $class = shift;
my $self = {};
return bless \$self, $class;
}
sub some_handler {
my $class = shift;
…
}
In the main program or calling class, then, you might do something
like:
# Save list of created plugin objects
my @plugs = plugins(optional => 'arguments');
…
my @values;
foreach my $p (@plugs) {
push @values, $p->some_handler()
if $p->can('some_handler');
}
Notes
- One quick way to determine this is to use the also built-in
Module::CoreList function first_release() from the command line:
perl
-MModule::CoreList -e "print
Module::CoreList->first_release('Module::Pluggable')"
A short tutorial.
Let's run through creating a Perl web application with Mojolicious
and styling by Zurb Foundation. We will
create this first as a full "application" and then as a "Lite" version.
Installing (Perlbrew and) Mojolicious
While perlbrew is not strictly required, the latest versions of Perl
have a number of features and optomizations that help Mojolicious.
There are two ways to install all this: Globally for all users (I
recommend this if you are administering the entire server, and want to
keep just one set of software) or in your home directory (best if you
share a server).
*Installing in your home directory *Following the instructions here
[perlbrew.pl], install Perlbrew into your home directory: something
like this:
\curl -L http://install.perlbrew.pl | bash
nice perlbrew -j 5 install perl-5.20.2
Note the 'nice' (to reduce impact on a running system) and the "-j
5" (to use up to five concurrent compilation threads) − although on
an active server, you might want to just use the default single
thread. Observe the final output of perlbrew: You will almost
certainly have to edit ~/.bash_profile
as it suggests, logout,
and then log back in to enable the perlbrew
command.
Now permanently switch to the new Perl, and install Mojolicious:
perlbrew switch perl-5.20.2
sudo sh -c "curl get.mojolicio.us | sh"
*Installing globally *Assuming a brand new machine (possibly a Linode
virtual machine), first we install the latest Mojolicious under
/local/bin ... if you don't do this as root this way, I recommend
you probably get a cpanminus version somewhere in your user home
directory.
sudo sh -c "curl get.mojolicio.us | sh"
Creating a Mojo "app"
OK now we can go into a working directory somewhere and type:
mojo generate app Test
which will create an entire tree of default files under the
subdirectory 'test' for a program called 'Test.'
At this point you should be able to start your example program:
cd Test
morbo script/test
and view the default text at http://localhost:3000
Adding Zurb Foundation to your "app"
Next we get the latest Foundation distribution from their website.
At the time of writing, this gave me foundation-5.3.1.zip. Create a
subdirectory called foundation
under the public directory and unzip
into there. This will create subdirectories css
and js
among a few
others.
wget <em>latest_foundation_link_from_above
</em>cd public
mkdir foundation
cd foundation
unzip ../../foundation*.zip
cd .. <em># back to Mojo project's public</em>
We are going to leave those files in a pristine tree so we can replace
them later, and create symbolics links to them. Note the slightly
curious use of relative paths in the symbolic links below. The multiple
../
are needed because symlinks are relative to the destination file,
not the directory where our shell happens to be when they are created.
Also, if only the destination directory and not a filename is given,
the destination filename is copied from the source (linked-to) file.
# Assuming the latest Foundation framework code
# is downloaded into the 'foundation' directory,
# and that we are currently in the 'public'
# directory in your generated mojo application,
# here we make symlinks from our document root
# into there, only for the files we actually use.
mkdir css
mkdir -p js/vendor
ln -s ../foundation/css/normalize.css css/
ln -s ../foundation/css/foundation.min.css css/
ln -s ../foundation/js/foundation.min.js js/
ln -s ../../foundation/js/vendor/jquery.js js/vendor/
ln -s ../../foundation/js/vendor/modernizr.js js/vendor/
It is worth a reminder that the syntax here is:
<tt>ln -s</tt> <em><small>{source (real file)} {destination (new link name)}</small></em>
Building the HTML for Foundation
Starting with the basic HTML from here:
http://foundation.zurb.com/docs/css.html
We copy some of the code from the original default.html.ep and create
the new templates/layouts/zurbish.html.ep as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- Zurb Foundation stuff -->
<meta name="viewport" content=
"width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/foundation.min.css">
<script src="js/vendor/modernizr.js"></script>
<!-- end Zurb -->
<title><%= title %></title>
</head>
<body>
<script src="js/vendor/jquery.js"></script>
<script src="js/foundation.min.js"></script>
<script>
$(document).foundation();
</script>
<%= content %>
</body>
</html>
Then in templates/example/welcome.html.ep we change the content to be
as follows:
% layout 'zurbish';
% title 'Welcome';
<h2><%= $msg %></h2>
This page was generated from the template "templates/example/welcome.html.ep"
and the layout "templates/layouts/zurbish.html.ep",
<a href="<%== url_for %>">click here</a> to reload the page or
<a href="/index.html">here</a> to move forward to a static page.
<div class="row">
<div class="small-2 columns">2 columns</div>
<div class="small-10 columns">10 columns</div>
</div>
<div class="row">
<div class="small-3 columns">3 columns</div>
<div class="small-9 columns">9 columns</div>
</div>
Now, http://localhost:3000
should give you the example text in a
very, very basic Foundation based layout. From here, you might want to
follow one of the excellent Mojolicious tutorials out there. Here is
Zurb's official guide to the Grid,
for example.
Also useful is this from "Zurb U"
which explains the small/medium/large grids. The one-line gist is:
If you don't specify small-# to a column, Foundation will assume
you mean "go full-width on small screens."
As a "Lite App"
For simplicity, here is basically the same program as a single file, in
the form of a boilerplate Mojolicious "Lite app":
#!/usr/bin/env perl
use Mojolicious::Lite;
get '/' => sub {
my $c = shift;
$c->render('index',
msg => 'Welcome to the Mojolicious real-time web framework!');
};
app->start;
__DATA__
@@ index.html.ep
% layout 'zurb';
% title 'Welcome';
<div class="row">
<h2><%= $msg %></h2>
<div class="small-2 columns">2 columns</div>
<div class="small-10 columns">10 columns</div>
</div>
<div class="row">
<div class="small-3 columns">3 columns</div>
<div class="small-9 columns">9 columns</div>
</div>
@@ layouts/zurb.html.ep
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- Zurb Foundation stuff -->
<meta name="viewport" content=
"width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/foundation.min.css">
<script src="js/vendor/modernizr.js"></script>
<!-- end Zurb -->
<title><%= title %></title>
</head>
<body>
<script src="js/vendor/jquery.js"></script>
<script src="js/foundation.min.js"></script>
<script>
$(document).foundation();
</script>
<%= content %>
</body>
</html>
If you save the above as example.pl
for example, then the command
morbo example.pl
should permit you to view the generated one-page site at http://localhost:3000
Next steps
In the next installment,
we will see how to better use Mojo's template system with Foundation.
Additional Resources
This turns out to be amazingly easy, at least with Debian 7.3.
First, instead of MySQL, I followed instructions at the MariaDB site: Setting
Up MariaDB Repositories.
Then:
$ sudo apt-get install libcatalyst-modules-perl
which installed over 200 modules, but what do you know:
$ catalyst.pl Foo
creates a Foo Catalyst application under the current directory.
Everything *Just Works. *Thanks to Debian and the folks who bring you
Catalyst.
Further reading:
UPDATE (April 2014): Catalyst seems a bit heavy for most of my needs.
I'm exploring mojolicious.