FastCGI overview

FastCGI is a way to have CGI scripts execute time-consuming code (like opening a database) only once, rather than every time the script is loaded. In technical terms, FastCGI is a language independent, scalable, open extension to CGI that provides high performance without the limitations of server specific APIs.

Difference between FCGI and CGI

CGI

CGI is a protocol for web servers to execute dynamic web programs.

CGI creates new processes for each request which makes CGI programs simple to implement, but limits efficiency and scalability. At high loads, CGI process creation overhead becomes significant.

FCGI

FCGI is a newer variation on CGI that helps to reduce overhead associated with CGI programs, allowing a server to handle more web page requests at once.

FCGI uses persistent processes to handle a series of requests. Each individual FastCGI process can handle many requests over its lifetime, thereby avoiding the overhead of per-request process creation and termination.

Differences

FCGI is an improved version of CGI that runs faster, however, since FCGI processes are always running, more memory is used by the server.

In general, FCGI is recommended.

Configuration details

This is the current FastCGI (mod_fastcgi) configuration at DreamHost:

FastCgiConfig -autoUpdate -initial-env RAILS_ENV=production -idle-timeout 60 -startDelay 10 -maxClassProcesses 2 -killInterval 300

These settings are almost exactly the default configuration for FastCGI.

On DreamHost private servers, FastCGI is handled by mod_fcgid rather than mod_fastcgi.

mod_fcgid is an Apache module providing a FastCGI interface. It's an alternative to mod_fastcgi that is specifically tuned for the dynamic FastCGI configuration used on DreamHost servers.

Making changes to your scripts

Structure of a FastCGI script

FastCGI scripts have two sections:

  1. Code that runs just once (like opening a database).
  2. Code that runs every time.

Here's an example with Perl:

#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
    $counter=0;

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;
while ( FCGI::accept() >= 0 ) {
     $counter++;
     print "Content-type:text/html\n\n";
     print "I have run $counter times.";
}

While you might think that you need to print the header only once, in fact the header must be included in the "run every time" section.

No exits

If your script terminates by some command (such as exit; or last; in Perl), the script starts over from scratch the next time it's run, losing the benefits of running certain code only once. Additionally, if a script is terminated this way it may not run again for several minutes.

The symptom is that the browser tries to load the page for a couple of minutes, finally giving up with "an error occurred while processing this directive". The error is even more frustrating because you (or your users) have to wait multiple minutes to get it.

The solution is to use whatever flow control is available in your programming language to have the script finish by itself. Here's a before and after example in Perl with some pseudocode:

Wrong way
#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
     (open a database)

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;
while ( FCGI::accept() >= 0 ) {
      print "Content-type:text/html\n\n";

      if (some test) { exit;}

      more code;
}
Right way
#!/usr/bin/perl

#-----------------------
#  CODE THAT RUNS ONCE
#-----------------------
     (open a database)

#---------------------------------
#  CODE THAT RUNS EVERY TIME
#---------------------------------

use FCGI;

while ( FCGI::accept() >= 0 ) {
      print "Content-type:text/html\n\n";

      if (some test) { goto(EXITLABEL) }

      more code;

      EXITLABEL: {}
}

Using $ENV{'QUERY_STRING'} instead of @ARGV

You cannot get the query string in FastCGI by using the @ARGV array. You must use $ENV{'QUERY_STRING'} instead.

Errors and troubleshooting

Bad scripts won't return an error immediately; you must wait a couple of minutes for the script to time out. If the script is on a web page, the page appears to hang – and even when the script times out, the actual error message might not be logged and you may only see a 500 error. This means that testing under FastCGI is rather impractical. Development should be done with standard CGI, or on your local computer. FastCGI should be added after the script has already been debugged.

Also, while it's tempting to develop on a live server, it's dangerous and makes you a bad neighbor for shared hosting.

To see immediately if a script will fail (won't check all cases because %ENV is different), test it from the command line:

[server]$ perl ~/example.com/myscript.fcgi

or, for deeper checking if you can use the debugger:

[server]$ perl -d ~/example.com/myscript.fcgi

If you've introduced an error into a script, fixing the error might not fix it immediately, because sometimes the server is still running an old version of the script from memory for various reasons. (The server is supposed to look at the modification date of the file so that it's always running the most recent version, but this is often not the case. When the server fails to do this, "touch"ing the file doesn't help, either.)

To make the server run the current version of the script, find the old process and kill it:

[server]$ killall -USR1 scriptname.fcgi     (replace scriptname.fcgi with the name of the process)

The above command may not always convince all the processes to stop. To force them to stop use:

[server]$ killall -9 scriptname.fcgi   (replace scriptname.fcgi with the name of the process)

Occasionally, you may need to use ruby1.8 as a task ID:

[server]$ killall -9 ruby1.8

My FastCGI Isn't working

Make sure that the script you are trying to execute is set as executable:

[server]$ chmod +x myscript.fcgi

Check the error log if you are getting the error:

[Fri Sep 05 11:55:03 2008] [error] [client 123.45.67.89] FastCGI: comm with (dynamic) server "/home/myaccount/example.com/myscript.fcgi" aborted: (first read) idle timeout (60 sec)

Make sure you check your file and directory permissions. The directory containing the fcgi, and the fcgi itself, must be owned by your default Unix group and be group-writable:

[server]$ chgrp -R `groups | awk '{print $1}'` ~/example.com/
[server]$ chmod -R g+w ~/example.com/

Also, check to see if you have a similar directive:

RewriteRule ^(.*)$ scriptname.cgi [QSA,L]

That needs to be changed to:

RewriteRule ^(.*)$ scriptname.fcgi [QSA,L]

Finally, try deleting all sessions in your /tmp folder (if you’re on a VPS or Dedicated server).

See also

Did this article answer your questions?

Article last updated .