Mojolicious / PSGI application on shared hosting

    A number of articles have already been written about Mojolicious from which you can get general impressions of this web framework. Reading publications, you can understand how easily the application, including PSGI, is deployed, scaled, interacts with web servers and can withstand high loads. All this is good, of course, but for some reason there is no article on how to run the application on an ordinary virtual hosting. Although, maybe it is not by the fact that it is indecent to do it simply?

    Requirements.



    Be that as it may, but shared hosting must satisfy some requirements.
    • Perl version 5.10 or higher is installed;
    • allowed the use of cgi-scripts;
    • supported by mod_rewrite;

    In general, that’s all. Of course, it’s good if you can use the space outside the web directory to store all the necessary modules there. We assume that you have already installed Mojolicious on your computer yourself, for example, using any of the articles with reviews of this web framework.

    To run the PSGI application on the hosting, Plack must be installed and mod_perl supported.

    Mojolicious application



    If you do not already have one, then I suggest having some fun and checking Habrahabr for tolerance. To do this, we will need Mojolicious itself, your favorite IDE and a little patience.

    Application wireframe


    The first step is to generate the application framework. Since we want to get beyond the limits of a single-line application and put an end to the confrontation between Dancer vs Mojolicious, we will abandon the Lite version:
    habra@cynovg-notebook:~$ mojo generate app Habra
      [mkdir] /home/habra/habra/script
      [write] /home/habra/habra/script/habra
      [chmod] habra/script/habra 744
      [mkdir] /home/habra/habra/lib
      [write] /home/habra/habra/lib/Habra.pm
      [mkdir] /home/habra/habra/lib/Habra
      [write] /home/habra/habra/lib/Habra/Example.pm
      [mkdir] /home/habra/habra/t
      [write] /home/habra/habra/t/basic.t
      [mkdir] /home/habra/habra/log
      [mkdir] /home/habra/habra/public
      [write] /home/habra/habra/public/index.html
      [mkdir] /home/habra/habra/templates/layouts
      [write] /home/habra/habra/templates/layouts/default.html.ep
      [mkdir] /home/habra/habra/templates/example
      [write] /home/habra/habra/templates/example/welcome.html.ep
    

    We delete the directories with examples if they interfere and proceed with the entertainment.

    Application Design


    So that the application would be even a little more serious than “Hello, World!”, I suggest using the Habrahabra search to practice skills. Namely, to request the user a search string, give it to Habr, receive a response and display it to the user.

    Let's start small, learn how to generate a search query input form and display a stub template as a reaction to receiving data from a user. To do this, you will need a route to the input form, the form template itself and the response stub.

    All the routes we have are stored in the Habra.pm module located in the lib directory, the contents of which after generation will look like this.
    package Habra;
    use Mojo::Base 'Mojolicious';
    # This method will run once at server start
    sub startup {
      my $self = shift;
      # Documentation browser under "/perldoc"
      $self->plugin('PODRenderer');
      # Router
      my $r = $self->routes;
      # Normal route to controller
      $r->get('/')->to('example#welcome');
    }
    1;
    

    Since we are engaged in search, it is logical to name our controller Search, and the routes to it, respectively, search # default and search # result. By default, we will display the input form:
      $r->route( '/' )->via('get')->to( 'search#default' );
    

    and create a template for the input form, placing it in /templates/search/deafult.html.ep:
    % layout 'default';
    % title 'Форма поискового запроса';
    

    Now, after we removed everything unnecessary from the Habra.pm module and changed the default route, our module should look like this:
    package Habra;
    use Mojo::Base 'Mojolicious';
    sub startup {
      my $self = shift;
      my $r = $self->routes;
      $r->route( '/' )->via('get')->to( 'search#default' );
    }
    1;
    

    We will check how it works by running a script from the command line from the directory of the same name:
    morbo script/habra 
    Server available at http://127.0.0.1:3000.
    

    Turning to it from a browser at 127.0.0.1haps000, our input form should be displayed, which, of course, leads to the crash of the application as soon as we are going to go somewhere. And this happens because we do not have a route to the control for the post method, which is used to transfer data from the input form. Add a route in the main module and a temporary stub template in the templates. To do this, add the line in the main module:
      $r->route( '/' )->via('post')->to( 'search#result' )
    

    and create a data output template, templates / search / result.html.ep
    % layout 'default';
    % title 'Результат поиска';
    

    If we check now how our application works, we will see that as a reaction to our desire to go somewhere, there will be a blank page with the heading “Search Result”.

    To achieve our goal, we will need to implement the result method in control, which would accept the request, send it to the Habr and convert the response from the Habr to a form convenient for us. To do this, create the lib / Habra / Search.pm module with the following contents:
    package Habra::Search;
    use Mojo::Base 'Mojolicious::Controller';
    sub result
    {
        my $self = shift;
        my $str  = $self->param( 'q' );
        my $ua  = Mojo::UserAgent->new;
        my $dom = $ua->get( 'http://habrahabr.ru/search/?q='.$str )->res->dom;
        my $pull = ();
        for my $raw ( $dom->find( 'div[id^="post"]' )->each )
            {
                my $header= $raw->find( 'a[class="post_title"]' )->first;
                push @$pull, {
                    title => $header->text,
                    url => $header->{href},
                    content => $raw->find( 'div[class^="content"]' )->first->text
                };
            }
        $self->render( result => $pull );
    }
    1;

    and complement the stub template to display the result of the request:
    % layout 'default';
    % title 'Результат поиска';
    
      % for my $row ( @$result ) {
    • <%= $row->{title} %>

      <%= $row->{content} %>

      Ссылка на статью: <%= $row->{url} %>

    • %}

    If there is any simpler or, in your opinion, more “correct” way to extract data, then I would love to know about it.

    We assume that this will be enough for the first acquaintance, but we still have not reached the main goal at this stage, since our application is still located on the local machine. It's time to launch it on a shared hosting.

    Publish Application



    At this stage, we have a hosting that meets the requirements and a working application. It remains the case for small, publish it. Oh yes, let's assume that the domain name is mojoex.am.pl, and the path to the site is /home/mojoex.am.pl/www.

    To run the application, you need to download the Mojolicious source codes, for example, from GitHub
    git clone https://github.com/kraih/mojo.git
    

    then remove everything superfluous from the distribution, leaving only the lib directory, since this is where all the modules are stored. In order not to get confused between the application modules and the modules of the Mojolishes itself, you can rename the lib directory for example, in mojo.

    The next step is to slightly modify the script that launches the application by adding a pointer to the directory with the Modzholisis modules and the application itself in its header and rename it to habra.cgi
    use lib ( '/home/mojoex.am.pl/mojo' );
    use lib ( '/home/mojoex.am.pl/lib' );
    

    The next step is to put the Mojolishes modules outside the site, along the path /home/mojoex.am.pl/mojo. In the same way, lay out application modules and templates, /home/mojoex.am.pl/lib and /home/mojoex.am.pl/templates, respectively. Also create a directory for logs, /home/mojoex.am.pl/log. But the script that starts the application must be placed in the directory /home/mojoex.am.pl/www/cgi-bin, with the right to execute.

    The final step is some magic with mod_rewrite. You need to create rules, for this we create a .htaccess file, which should be located in the /home/mojoex.am.pl/www directory, with the following contents:
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ /cgi-bin/habra.cgi/$1 [L]
    RewriteRule ^$ /cgi-bin/habra.cgi [L]
    


    frenzytechnix Tips that if mod_perl is installed on the hosting, then we can run the PSGI application. To do this, specify the following in .htaccess:
    
        $ENV{PLACK_ENV} = 'production';
        $ENV{MOJO_HOME} = '/home/mojoex.am.pl';
        $ENV{MOJO_TEMPLATE_CACHE} = 0;
        $ENV{PERL5LIB} .= '/home/mojoex.am.pl/lib;/home/mojoex.am.pl/mojo'
    
        SetHandler perl-script
        PerlHandler Plack::Handler::Apache2
        PerlSetVar psgi_app /home/mojoex.am.pl/www/cgi-bin/habra
    


    Everything, on this our ordeals should end, as you can see by going to the main page of the site. If everything is done correctly, you should be prompted to enter data for the search. If this did not happen, then you should look at the reason in the server error logs, most likely the problem is access to the application launch script.

    Summary



    As a result, the hosting structure should look similar:
    /home/mojoex.am.pl/                             # корень сайта
    /home/mojoex.am.pl/mojo/                        # директория с модулями Mojolicious
    /home/mojoex.am.pl/lib/                         # директория с модулями приложения
    /home/mojoex.am.pl/log/                         # директория с логами работы приложения
    /home/mojoex.am.pl/www/.htaccess                # файл с правилами для mode_rewrite
    /home/mojoex.am.pl/www/cgi-bin/habra.cgi        # скрипт, запускающий приложение
    

    Static files such as styles, images, etc. are stored in the usual way, thanks to the rules in .htaccess they are ignored when redirecting. When accessing non-existent resources, a redirect to the application takes place, which independently decides what to do. If an appeal occurs along the specified paths, then control is transferred to control, otherwise an error message is generated, which can be generated independently.

    If someone may find the code fragment furious, or there are some incomprehensible points, comments or suggestions, leave comments.

    Also popular now: