Telephone +44(0)1524 64544
Email: info@shadowcat.co.uk

mstpan 2 - Web Deployment

Tue Dec 2 21:00:00 2014

Introductory waffle

I told you I'd do deployment next.

Note that this is basically about servers and how to connect stuff together, not so much about how your app code gets onto the system in the first place. That particular princess is in a different castle.


mstpan 2 - Web Deployment

mod_perl

Really? In 2014?

Look. mod_perl was written as a means to write apache modules in perl. It's awesome at that. Seriously. You can do some truly batshit insane things that way and segfault a lot less than you would trying to do them in C.

But. When it was just 'some dynamic pages', regarding that content generator as a web server extension made perfect sense. Now that a lot of the things we're deploying are apps where a complete chunk of the URL space is served by the code and the static file serving part is basically an incidental thing needed by the app ... this is not a good strategy.

You don't want your application mashed into your web server. You really don't.

See Plack::App::FakeApache for how to escape to PSGI land.

CGI

Really? In 2014?

Actually, yes. Take a moment while the palpitations subside.

There's nothing wrong with the CGI protocol itself for the limited things that it does, which basically boils down to running a process per HTTP request, on demand.

If your app is very rarely hit, and can respond fast enough from cold that the lack of persistence doesn't matter, then it's a ridiculously simple option that's nice and easy to test from the command line - and puts no load on the system at all when it isn't actually doing anything.

The contact form on the front page is the one dynamic part of this site. It POSTs to a Web::Simple application deployed as a CGI script. Being a programming consultancy, most people email us directly, so it fits 'rarely hit'. Plus, being able to rsync over the app plus its local::lib and have that be used for the next request without having had to configure anything keeps things nice and simple.

Don't try this with Catalyst. Catalyst front-loads as much setup as it can in return for faster runtime. Under CGI, this does not end well.

FastCGI

The protocol is kinda ugly, SCGI should've won. The perl module is more than kinda ugly, but if you treat it as a black box and understand that attempting to view its source may invite elder gods to snack upon your neurons, that's more a potential than an actual problem.

But it's old, solid and works. I'm pretty sure it's been declared dead at least once, which is usually a requirement for a technology to be production grade stable.

Dynamic FastCGI is hilarious, and largely only useful for shared hosting platforms. Basically that means you fire up a FastCGI process on demand and then keep it around for a bit in case you need it again. The results tend to range from "the first request and every fifth subsequent one take 6s" to "you did a lot of work to not be noticeably faster than CGI".

Under apache, this is all that mod_fcgid supports. Assuming you aren't dreamhost, go get yourself mod_fastcgi.

FastCGI started by the web server is quite reasonable, provided you're ok with the app running as the same user. And provided you're ok with the app restarting when the webserver's config gets reloaded.

A separate FastCGI daemon with a unix socket connecting it to the webserver is my favourite option; for apache, you wanted FastCgiExternalServer. Then you write a quick Daemon::Control script to get a working init script, and it all works nicely.

Neat thing: using a unix socket means that you don't need Linux 2.yesterday to be able to have two copies of the app listening to the same socket, which means you can do zero downtime restarts with a little cleverness.

For details of doing this with apache and nginx, read the Catalyst FastCGI deployment docs. They work fine with other PSGI based apps, and from simple age are more battle tested than everybody else's.

Starman

Starman is the most commonly used httpd for deploying PSGI apps. It serves HTTP by itself, it's a preforking daemon, you can run it on port 80 if you really want to (and if static content is served from elsewhere and you're behind a load balancer, that's much less insane than it sounds).

It can also (trumpets) bind to a UNIX socket, for nginx to talk to, letting you secure it with normal permissions and do the zero downtime restart trick easily. Honestly, for nginx I'd default to this configuration (again w/Daemon::Control) because people seem to find http proxying much more comprehensible on average (use socat for your telnet 80 equivalent).

Under apache, I much prefer FastCgiExternalServer, because every time I use mod_proxy I come away thinking I'd've had more fun by sticking a sensitive part of my anatomy in a bag of razorblades.

Oh. Starman also works with Server::Starter, which for the 'answering 80' use case becomes a really nice deployment strategy.

Plack::Middleware::ReverseProxy and ::ReverseProxyPath are likely to be your friend if you find your application is generating URIs to the backend server rather than the original request host/path.

Hypnotoad

This is the Mojolicious server. If you're using Mojolicious, you should probably ignore everything else and use this. If you think you have a really good reason for not doing that, Mojolicious still supports PSGI. But you probably don't. Consider asking the mailing list before risking unexpected razorblade related incidents.

PSGI Async

Built on AnyEvent: Twiggy

Built on IO::Async: Net::Async::HTTP::Server::PSGI

I can't entirely understand why one would ever want to use an async server that isn't built using the same async system as your app's using. But even if one did, one would be wise to consider one of those two anyway.

Summary

Lightweight and rarely hit? CGI

Using apache? FastCgiExternalServer

Using nginx? Starman against a unix socket

Using a separate load balancer? Starman+Server::Starter over TCP

Using Mojolicious? Hypnotoad

Using mod_perl? Run while you still can ...

Next time: XML

-- mst, out.