Trying out mod_fcgid

mod_fcgid is an Apache httpd module that sets up a separate daemon for processing CGI requests. It’s like mod_cgid but it keeps a pool of processes running rather than spin up one each time a script needs execution. SpringSource ERS 4 comes with it but you have to enable the module and configure.

Official docs: http://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html

Perl

The first hurdle on CentOS with Perl was that FCGI.pm wasn’t installed nor evidently available from yum. A quick trip to CPAN solved that.

sudo cpan install FCGI

I set up the first Perl example from the docs and, having obtained a 503 Service Temporarily Unavailable was greeted in the logs with:

[warn] mod_fcgid: can’t apply process slot for /home/luke/ERS-4.0.2/servers/test-fcgid/cgi-bin/perl/printenv.pl

Well, seems like more than a warning to me. Given that only qualified as a warning, I set LogLevel info and got some more info about what was going on:

[info] mod_fcgid: server vm-centos-ers402.sosiouxme.lan:/home/luke/ERS-4.0.2/servers/test-fcgid/cgi-bin/perl/printenv.pl(17470) started
[info] mod_fcgid: process /home/luke/ERS-4.0.2/servers/test-fcgid/cgi-bin/perl/printenv.pl(17469) exit(server exited), terminated by calling exit(), return code: 255

This message was repeated with increasing numbers until the request timed out. Calling exit() with return code 255 is bad, but what am I supposed to about it? The processes are getting created, and sockets are being created in the fcgidsock directory. Pushing LogLevel to debug gets me a little more info:

[debug] fcgid_proc_unix.c(537): Connection refused: mod_fcgid: can’t connect unix domain socket: /home/luke/ERS-4.0.2/servers/test-fcgid/logs/safe/fcgidsock/18496.3

[warn] mod_fcgid: can’t apply process slot for /home/luke/ERS-4.0.2/servers/test-fcgid/cgi-bin/perl/printenv.pl

Call me crazy, but it seems to me these should all have been [error]-level messages (except for the first [info] one about starting a process). Something definitely going wrong. Searching Google brought up some people having the same problems; most seemed to be related to permissions (either file or selinux). As far as I can tell these aren’t relevant.

I noticed that fcgid was creating a file fcgid_shm and a directory fcgidsock in my logs directory. ERS has a standard location for things like this (logs/safe/) so I added directives to put them there. Also as requests would continue to try and fail for 40 seconds I added a timeout directive to limit this to 5 seconds. Not that it helped but it made me feel better:

FcgidIPCDir logs/safe/fcgidsock
FcgidProcessTableFile logs/safe/fcgid_shm
FcgidIOTimeout 5

A simple tip from this wiki (thanks!) helped me out: my script wasn’t marked as executable. It worked fine with a little chmod +x action. OK, but that’s sure a funny way to tell me about it.

Python

Frustrated with this, I decided to try python, as a coworker seemed to have gotten that working easily enough. First I tried the “lazy” example at this nice intro, with only minor modifications for my location. This involves creating the fcgi.py library and the simple “Hello World” app.py script. No luck:

[info] mod_fcgid: server vm-centos-ers402.sosiouxme.lan:/home/luke/ERS-4.0.2/servers/test-fcgid/cgi-bin/python/app.py(29968) started
[warn] mod_fcgid: read data timeout in 40 seconds
[error] Premature end of script headers: app.py
[info] mod_fcgid: process /home/luke/ERS-4.0.2/servers/test-fcgid/cgi-bin/python/app.py(29968) exit(communication error), terminated by calling exit(), return code: 0

And what’s more frustrating, this doesn’t match anything in the (probably otherwise helpful) troubleshooting section. I can see that no Process Manager is getting created. Alright, this document is a year and a half old, but surely it’s not that far off… what gives? So I started a serious read-through and learned about the different modes that can be used here (static, dynamic, external), and saw that the mode being used in app.py was static. I could see /tmp/fcgi.sock being created (and in fact, left behind) but nothing was happening, so I thought I’d just try dynamic mode and see. That involves simply changing this app.py line:

fcgi.WSGIServer(app, bindAddress = ‘/tmp/fcgi.sock’).run()

to this:

fcgi.WSGIServer(app).run()

For good measure, I restarted the server. And suddenly app.py is working. Nice to have some success finally! Contrary to what the intro said, ps doesn’t show the server created until I actually visit the script, which makes sense. If I run a second script, app2.py, I get a separate process created for that. If I hammer the script with “ab -c 50” I get 15 or so python processes created, so there is a limit. Also, the processes all die off eventually unless I configure them otherwise.

This second intro glosses over the configuration but provides another dynamic example (this time installing flup to provide the FastCGI interface). That works fine too. Needed to have yum install python-setuptools so I could use the easy_install to install the flup egg (thanks to this blog for introducing me).

PHP

I followed the example from the official mod_fcgid docs. This has some extra directives, apparently to compensate for some PHP oddities. Also it requires a wrapper script, and a php-cgi executable. For CentOS, php-cgi happens to be supplied by the php-cli package. Everything worked pretty much out of the box as described.

Ruby

Strangely, all the articles for running Ruby on mod_fcgid seem to be from 2006 and only refer to Rails. There are other ways to serve web content from a Ruby script, right? Right? *crickets*

So anyway, the first thing I discovered is that, not surprisingly, the version of Ruby that ships with RHEL 5 (and thus CentOS 5) is too old to run a modern Rails. What’s surprising, actually, is that the cutoff is so close; modern Rails/gems/etc. requires Ruby 1.8.6, while RHEL 5 bundles 1.8.5. It’s almost like they did it just to spite RHEL users. Though more likely, RHEL won’t bundle 1.8.6 because it’s too different from 1.8.5 and would break existing Ruby scripts, if any are actually being used on RHEL 5.

So I installed from source. I also tried to install rubygems from source. But here I ran into problems (zlib issues), and frankly I think trying to do this with RHEL 5 is probably just a really bad idea. There’s simply no way to follow the Red Hat way of configuring a system (which if you’re paying for RHEL, you want to do) and getting a recent Rails on RHEL 5. Use Fedora, or hope that RHEL 6 supplies a newer version of Ruby and some relevant gems. Maybe I’ll try that and update this later.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: