Running Nagios3 under Nginx & FastCGI

Wednesday, July 7th, 2010

It is quite possible to run Nagios3’s web interface directly from Nginx and a FastCGI server, rather than having to involve a web application server like Apache. This is useful if you want to preserve memory on your machine, for example.

First of all, we ask Nginx to serve the static files for the Nagios web interface. In Debian/Ubuntu, these live in /usr/share/nagios3/htdocs and /usr/share/nagios3/stylesheets, which is a little awkward, but just the sort of thing that the rewrite command is for …

    location / {
        root /usr/share/nagios3/htdocs;
        index index.html;

        rewrite ^/nagios3/stylesheets/(.*)$ /../stylesheets/$1 break;
        rewrite ^/nagios3/(.*)$ /$1 break;
    }

Next, we tell Nginx to send requests for CGI pages down to a FastCGI server :-

    location ~ \.cgi$ {
        root /usr/lib/cgi-bin/nagios3;
        include /etc/nginx/fastcgi_params;

        rewrite ^/cgi-bin/nagios3/(.*)$ /$1;

        auth_basic "Nagios";
        auth_basic_user_file /etc/nagios3/htpasswd.users;

        fastcgi_pass 127.0.1.1:8998;
        fastcgi_param SCRIPT_FILENAME /usr/lib/cgi-bin/nagios3$fastcgi_script_name;
        fastcgi_param AUTH_USER       $remote_user;
        fastcgi_param REMOTE_USER     $remote_user;
    }

We need to make sure that these requests are under authentication, and that we pass the authenticated username to the CGI script properly, hence the auth_basic and fastcgi_param AUTH_USER lines.

That’s Nginx taken care of, but we also need to make sure there’s a generic FastCGI server running on the specified address/port. No configuration is necessary, as we’re passing everything we need, including the script name. fcgiwrap comes recommended on the Nginx wiki.

/usr/bin/spawn-fcgi -a 127.0.1.1 -p 8998 \
-u www-data -g www-data \
-f /usr/local/bin/fcgiwrap -P /var/run/fcgiwrap.pid

And that’s all you need!

Testing a FastCGI service

Wednesday, July 7th, 2010

If you have a FastCGI service running, normally you just talk to it through the front-end web server. However, for testing purposes you should send requests directly to the fastcgi server.

Getting this done isn’t terribly obvious, as the FastCGI protocol is not in plain text you can’t just telnet to the server and enter commands, the way you can with HTTP. There is a useful command, cgi-fcgi that comes from the libfcgi package on Debian/Ubuntu (and probably in similar packages in other distros), but the man page assumes you already know a lot more about FastCGI than you probably needed to set something up in the first place!

From http://gist.github.com/mpasternacki comes a short wrapper script to invoke cgi-fcgi to send a simple request - http://gist.github.com/209446. This script sets a bunch of environment variables that the fcgi script may require up front.

Here’s a simpler example. I have a FastCGI server running on 127.0.1.1 port 8998. I used lighttpd’s spawn-fcgi to start up an instance of fcgiwrap, a minimal fcgi processor recommended on the Nginx wiki.

/usr/bin/spawn-fcgi -a 127.0.1.1 -p 8998 \
-u www-data -g www-data \
-f /usr/local/bin/fcgiwrap -P /var/run/fcgiwrap.pid

Then, I use cgi-fcgi to connect to the port, and see what I get back.

$ cgi-fcgi -bind -connect 127.0.1.1:8998
Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?
Status: 403 Forbidden
Content-type: text/plain

403

This is enough to confirm that fcgiwrap is running OK, but doesn’t tell us if it can actually carry out any work. I’ll ask it to run a Nagios CGI command :-

$ DOCUMENT_ROOT=/var/www \
SCRIPT_FILENAME=/usr/lib/cgi-bin/nagios3/tac.cgi \
cgi-fcgi -bind -connect 127.0.1.1:8998
getcgivars(): Unsupported REQUEST_METHOD -> ''

I'm guessing you're trying to execute the CGI from a command line.
In order to do that, you need to set the REQUEST_METHOD environment
variable to either "GET", "HEAD", or "POST".  When using the
GET and HEAD methods, arguments can be passed to the CGI
by setting the "QUERY_STRING" environment variable.  If you're
using the POST method, data is read from standard input.  Also of
note: if you've enabled authentication in the CGIs, you must set the
"REMOTE_USER" environment variable to be the name of the user you're
"authenticated" as.

Excellent, this error message looks like it has come from the actual CGI command itself. Let’s set a couple more variables to help it work … let’s add REQUEST_METHOD as the error message suggested.

$ REQUEST_METHOD=GET DOCUMENT_ROOT=/var/www \
SCRIPT_FILENAME=/usr/lib/cgi-bin/nagios3/tac.cgi \
cgi-fcgi -bind -connect 127.0.1.1:8998

Cache-Control: no-store
Pragma: no-cache
Refresh: 90
Last-Modified: Wed, 07 Jul 2010 01:27:16 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-type: text/html

...

I’ll spare you the rest of the HTML output. This shows us a way of using a simple command-line test to verify that a FastCGI service is running correctly, without involving any front-end webserver. This is useful if you’re getting stuck setting up the front-end webserver, or if you like to have intelligent service dependency monitoring that can diagnose problems more precisely.