FastCGI

Quicker startup for CGI programs

After you've written a few web applications, you'll be aware of the performance limitations of the standard CGI ("common gateway interface") protocol by which web servers call user programs to generate pages. CGI is easy to use, but that's about all that can be said for it; a webserver must fork and execute an instance of a CGI script for each page view, and once your CGI programs become complicated, this can impose a substantial overhead. For most sites, this isn't a problem, but CGI is a big limitation for busy sites.

FastCGI is an alternative to CGI which overcomes its performance problems. Rather than invoking a script or program once for each web request, FastCGI maintains persistent "server" processes which can handle numerous requests. The web server communicates with these processes over TCP or UNIX-domain sockets using an open protocol. Unlike mod_perl, mod_python, etc., which run user code inside the webserver, FastCGI keeps users' code separate, which is more secure and reliable. Most scripting languages have support for FastCGI, and present it with the same interface as regular CGI. You can use FastCGI for hosting dynamic content with Mythic Beasts shell accounts, but we recommend that you don't unless it's absolutely necessary, since doing so requires additional setup and can make debugging problems harder. Unless your site really is very busy, we're likely to respond to support requests about FastCGI by recommending that you use normal CGI instead.

To use FastCGI, you need to arrange for the webserver to run your scripts as FastCGI server processes. It is easiest to do this with a .htaccess file. If you want a whole directory of scripts to be invoked as FastCGI servers, then use something like this:

Options +ExecCGI
SetHandler fastcgi-script

Or, to run only scripts with a certain suffix - e.g., .fcgi - as FastCGI servers, use:

Options +ExecCGI
AddHandler fastcgi-script .fcgi

As with normal CGI scripts, you need to take care with the permissions on scripts used as FastCGI servers.

Examples

Here are some trivial examples of scripts adapted for use under FastCGI. In each case, the modified version of the script will work either as a CGI or a FastCGI script:

CGIFastCGI
Perl: the standard distribution contains the CGI::Fast module, which has an interface very similar to that for standard CGI. The changes are mostly trivial:
#!/usr/bin/perl -w
use strict;
use CGI;

my $q = new CGI();

print $q->header(),
        $q->start_html('Test CGI script'),
        $q->p('Hello! The time is',
            scalar(localtime(time())),
            'and your IP address is',
            $q->remote_addr(),
        $q->end_html();
#!/usr/bin/perl -w
use strict;
use CGI;
use CGI::Fast;

while (my $q = new CGI::Fast()) {
    print $q->header(),
            $q->start_html('Test CGI script'),
            $q->p('Hello! The time is',
                scalar(localtime(time())),
                'and your IP address is',
                $q->remote_addr(),
            $q->end_html();
}
Python: there are several modules for FastCGI support. We've installed fcgi.py from Total Control Software (no longer supported, but works fine). You can use any of the others if you install it in your own home directory. There are more changes than in the perl case, but the script is basically the same, and the new one still works under normal CGI:
#!/usr/bin/python

import cgi
import os
import time

print '''Content-Type: text/html

<html><head><title>
Test CGI Script
</title></head><body>
<p>Hello! The time is'''
print time.asctime(), 'and your IP address is',
print environ['REMOTE_ADDR'], '</body><html>'
#!/usr/bin/python

import fcgi
import os
import time

while fcgi.isFCGI():
    request = fcgi.Accept()
    request.out.write('''Content-Type: text/html

<html><head><title>
Test CGI Script
</title></head><body>
<p>Hello! The time is''')
    request.out.write(time.asctime(), 'and your IP address is')
    request.out.write(request.env['REMOTE_ADDR'], '</body><html>')
    request.Finish()
PHP: see our PHP specific notes. You don't need to make any changes to your code, but some changes to your webserver config are necessary.
C/C++: generally there's no need to write web applications in C or C++, and we recommend that you don't; but sometimes it's useful (for instance if you need to generate images on-demand or something similar where scripting languages just aren't fast enough). Conversion to FastCGI operation is trivial; you just need to make the changes below and compile your code with -lfcgi:
#include <stdio.h>
#include <time.h>

int main(void) {
    struct tm *t;
    time_t T;
    time(&T);
    t = localtime(&T);
    printf("<html><head><title>"
            "Test CGI Script"
            "</title></head><body>"
            "<p>Hello! The time is %s, "
            "and your IP address is %s.</p>"
            "</body></html>",
            asctime(t),
            getenv("REMOTE_ADDR"));
}
#include <fcgi_stdio.h>
#include <time.h>

int main(void) {
    struct tm *t;
    time_t T;
    while (FCGI_Accept() >= 0) {
        time(&T);
        t = localtime(&T);
        printf("<html><head><title>"
                "Test CGI Script"
                "</title></head><body>"
                "<p>Hello! The time is %s, "
                "and your IP address is %s.</p>"
                "</body></html>",
                asctime(t),
                getenv("REMOTE_ADDR"));
    }
}

Problems

The most serious problem with writing and using FastCGI programs is debugging them. As with a normal CGI program, you can log diagnostics to the server error log; since FastCGI programs run for extended periods of time, you may also be able to use an interactive debugger to study the behaviour of your program. Against this is the problem that, unlike regular CGI programs, any changes you make won't immediately take effect, unless you arrange the accept loop in your program to re-exec itself whenever it detects that the script file has changed on disk. If you don't do that, you'll need to terminate your script (using the kill or killall commands) and let the webserver restart the new copy. But if you do this too often, or if your script dies of its own accord, the webserver will conclude that it's not working properly and hold off restarting it for a while.

So, you should set up a test environment for development (this is good advice in any case), and do the initial work on your scripts under a CGI environment rather than FastCGI.

For more advice, take a look at the resources on the FastCGI home page.