Mojolicious

 view release on metacpan or  search on metacpan

lib/Mojolicious/Guides/Cookbook.pod  view on Meta::CPAN

  CMD ./myapp.pl prefork

It uses the latest L<Perl container|https://hub.docker.com/_/perl> from Docker Hub, copies all the contents of your
application directory into the container, installs CPAN dependencies with L<App::cpanminus>, and then starts the
application on port C<3000> with the pre-forking web server. With L<Mojolicious::Command::Author::generate::dockerfile>
there is also a helper command to generate a minimal C<Dockerfile> for you.

  $ ./myapp.pl generate dockerfile
  ...

To build and deploy our container there are also many options available, here we will simply use Docker.

  $ docker build -t myapp_image .
  ...
  $ docker run -d -p 3000:3000 --name myapp_container myapp_image
  ...

And now your web application should be deployed as a container under C<http://127.0.0.1:3000>. For more information and
many more container deployment options we recommend the L<Docker|https://docs.docker.com/> and
L<Kubernetes|https://kubernetes.io/docs/> documentation.

=head2 Hypnotoad

L<Hypnotoad|Mojo::Server::Hypnotoad> is based on the L<Mojo::Server::Prefork> web server, and adds some features
especially optimized for high availability non-containerized production environments. To start applications with it you
can use the L<hypnotoad> script, which listens on port C<8080>, automatically daemonizes the server process and defaults
to C<production> mode for L<Mojolicious> and L<Mojolicious::Lite> applications.

  $ hypnotoad ./script/my_app

Many configuration settings can be tweaked right from within your application with L<Mojolicious/"config">, for a full
list see L<Mojo::Server::Hypnotoad/"SETTINGS">.

  use Mojolicious::Lite;

  app->config(hypnotoad => {listen => ['http://*:80']});

  get '/' => {text => 'Hello Wor...ALL GLORY TO THE HYPNOTOAD!'};

  app->start;

Or just add a C<hypnotoad> section to your L<Mojolicious::Plugin::Config>, L<Mojolicious::Plugin::JSONConfig> or
L<Mojolicious::Plugin::NotYAMLConfig> configuration file.

  # myapp.conf
  {
    hypnotoad => {
      listen  => ['https://*:443?cert=/etc/server.crt&key=/etc/server.key'],
      workers => 10
    }
  };

But one of its biggest advantages is the support for effortless zero downtime software upgrades (hot deployment). That
means you can upgrade L<Mojolicious>, Perl or even system libraries at runtime without ever stopping the server or
losing a single incoming connection, just by running the command above again.

  $ hypnotoad ./script/my_app
  Starting hot deployment for Hypnotoad server 31841.

You might also want to enable proxy support if you're using L<Hypnotoad|Mojo::Server::Hypnotoad> behind a reverse
proxy. This allows L<Mojolicious> to automatically pick up the C<X-Forwarded-For> and C<X-Forwarded-Proto> headers.

  # myapp.conf
  {hypnotoad => {proxy => 1}};

To manage L<Hypnotoad|Mojo::Server::Hypnotoad> with systemd, you can use a unit configuration file like this.

  [Unit]
  Description=My Mojolicious application
  After=network.target

  [Service]
  Type=forking
  User=sri
  PIDFile=/home/sri/myapp/script/hypnotoad.pid
  ExecStart=/path/to/hypnotoad /home/sri/myapp/script/my_app
  ExecReload=/path/to/hypnotoad /home/sri/myapp/script/my_app
  KillMode=process

  [Install]
  WantedBy=multi-user.target

=head2 Zero downtime software upgrades

L<Hypnotoad|Mojo::Server::Hypnotoad> makes zero downtime software upgrades (hot deployment) very simple, as you can see
above, but on modern operating systems that support the C<SO_REUSEPORT> socket option, there is also another method
available that works with all built-in web servers.

  $ ./script/my_app prefork -P /tmp/first.pid -l http://*:8080?reuse=1
  Web application available at http://127.0.0.1:8080

All you have to do, is to start a second web server listening to the same port, and stop the first web server
gracefully afterwards.

  $ ./script/my_app prefork -P /tmp/second.pid -l http://*:8080?reuse=1
  Web application available at http://127.0.0.1:8080
  $ kill -s TERM `cat /tmp/first.pid`

Just remember that both web servers need to be started with the C<reuse> parameter.

=head2 Nginx

One of the most popular setups these days is L<Hypnotoad|Mojo::Server::Hypnotoad> behind an L<Nginx|https://nginx.org>
reverse proxy, which even supports WebSockets in newer versions.

  upstream myapp {
    server 127.0.0.1:8080;
  }
  server {
    listen 80;
    server_name localhost;
    location / {
      proxy_pass http://myapp;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
    }
  }

=head2 Apache/mod_proxy

Another good reverse proxy is L<Apache|https://httpd.apache.org> with C<mod_proxy>, the configuration looks quite
similar to the Nginx one above. And if you need WebSocket support, newer versions come with C<mod_proxy_wstunnel>.

  <VirtualHost *:80>
    ServerName localhost
    <Proxy *>
      Require all granted
    </Proxy>
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyPass /echo ws://localhost:8080/echo
    ProxyPass / http://localhost:8080/ keepalive=On
    ProxyPassReverse / http://localhost:8080/
    RequestHeader set X-Forwarded-Proto "http"
  </VirtualHost>

=head2 Apache/CGI

C<CGI> is supported out of the box and your L<Mojolicious> application will automatically detect that it is executed as
a C<CGI> script. Its use in production environments is discouraged though, because as a result of how C<CGI> works, it
is very slow and many web servers are making it exceptionally hard to configure properly. Additionally, many real-time
web features, such as WebSockets, are not available.

  ScriptAlias / /home/sri/my_app/script/my_app/

=head2 Envoy

L<Mojolicious> applications can be deployed on cloud-native environments that use L<Envoy|https://www.envoyproxy.io>,
such as with this reverse proxy configuration similar to the Apache and Nginx ones above.

  static_resources:
    listeners:
    - name: listener_0
      address:
        socket_address: { address: 0.0.0.0, port_value: 80 }
      filter_chains:
      - filters:
        - name: envoy.filters.network.http_connection_manager
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
            codec_type: auto
            stat_prefix: index_http
            route_config:
              name: local_route
              virtual_hosts:
              - name: service
                domains: ["*"]
                routes:
                - match:
                    prefix: "/"
                  route:
                    cluster: local_service
            upgrade_configs:
            - upgrade_type: websocket
            http_filters:
            - name: envoy.filters.http.router
              typed_config:
    clusters:
    - name: local_service
      connect_timeout: 0.25s
      type: strict_dns
      lb_policy: round_robin
      load_assignment:
        cluster_name: local_service
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address: { address: mojo, port_value: 8080 }

While this configuration works for simple applications, Envoy's typical use case is for implementing proxies of
applications as a "service mesh" providing advanced filtering, load balancing, and observability features, such as
seen in L<Istio|https://istio.io/latest/docs/ops/deployment/architecture/>. For more examples, visit the
L<Envoy documentation|https://www.envoyproxy.io/docs/envoy/latest/start/start>.

=head2 PSGI/Plack

L<PSGI> is an interface between Perl web frameworks and web servers, and L<Plack> is a Perl module and toolkit that
contains L<PSGI> middleware, helpers and adapters to web servers. L<PSGI> and L<Plack> are inspired by Python's WSGI
and Ruby's Rack. L<Mojolicious> applications are ridiculously simple to deploy with L<Plack>, but be aware that many
real-time web features, such as WebSockets, are not available.

  $ plackup ./script/my_app

L<Plack> provides many server and protocol adapters for you to choose from, such as C<FCGI>, C<uWSGI> and C<mod_perl>.

  $ plackup ./script/my_app -s FCGI -l /tmp/myapp.sock

The C<MOJO_REVERSE_PROXY> environment variable can be used to enable proxy support, this allows L<Mojolicious> to
automatically pick up the C<X-Forwarded-For> and C<X-Forwarded-Proto> headers.

  $ MOJO_REVERSE_PROXY=1 plackup ./script/my_app

If an older server adapter is unable to correctly detect the application home directory, you can simply use the
C<MOJO_HOME> environment variable.

  $ MOJO_HOME=/home/sri/my_app plackup ./script/my_app

There is no need for a C<.psgi> file, just point the server adapter at your application script, it will automatically
act like one if it detects the presence of a C<PLACK_ENV> environment variable.

=head2 Plack middleware

Wrapper scripts like C<myapp.fcgi> are a great way to separate deployment and application logic.

  #!/usr/bin/env plackup -s FCGI
  use Plack::Builder;

  builder {
    enable 'Deflater';
    require './script/my_app';
  };

L<Mojo::Server::PSGI> can be used directly to load and customize applications in the wrapper script.

  #!/usr/bin/env plackup -s FCGI
  use Mojo::Server::PSGI;
  use Plack::Builder;

  builder {
    enable 'Deflater';
    my $server = Mojo::Server::PSGI->new;
    $server->load_app('./script/my_app');
    $server->app->config(foo => 'bar');
    $server->to_psgi_app;
  };

But you could even use middleware right in your application.

  use Mojolicious::Lite -signatures;
  use Plack::Builder;

  get '/welcome' => sub ($c) {
    $c->render(text => 'Hello Mojo!');
  };

  builder {
    enable 'Deflater';
    app->start;
  };

=head2 Rewriting

Sometimes you might have to deploy your application in a blackbox environment where you can't just change the server
configuration or behind a reverse proxy that passes along additional information with C<X-Forwarded-*> headers. In such
cases you can use the hook L<Mojolicious/"before_dispatch"> to rewrite incoming requests.

  # Change scheme if "X-Forwarded-HTTPS" header is set
  $app->hook(before_dispatch => sub ($c) {
    $c->req->url->base->scheme('https')



( run in 0.711 second using v1.01-cache-2.11-cpan-817d5f8af8b )