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 )