Guides/FastCGI

From J Wiki
Jump to navigation Jump to search

J can be used for FastCGI programming. Here are some considerations and examples.

Note: the examples assume Windows and Linux, but MacOSX would be similar - feel free to add MacOSX-specific references.


What is FastCGI

The FastCGI protocol is a replacement for the Common Gateway Interface (CGI) protocol. It is a standard for applications to interface with HTTP servers. Instead of creating a new process for every request, FastCGI uses a single persistent process which handles many requests over its lifetime.

There are a number of ways of generating dynamic web content:

1. Classic CGI - where the web server executes an external application which generates the content. A new instance of the program is started for each request. 2. mod_language - where the web server loads a script interpreter (like PHP) into its address space and executes it there. 3. SCGI / SCGI and FastCGI / FastCGI - where the application runs separately from the web server and the two communicate over TCP.

Visualize two process trees:

httpd (parent)
|
+-- httpd (child)
|
+-- httpd (child)

      :
communication over TCP or Unix socket file
      :

fcgi_server (parent)
|
+-- fcgi_server (child)

Why FastCGI?

FastCGI is similar to SCGI but more complicated. However there are more HTTP servers that implement FastCGI mainly for supporting PHP which is a FastCGI server itself.

Note that FastCGI is a protocol. It is not specific to PHP. You can write an FastCGI server in any implementation language, and as long as you stick to the protocol, HTTP server with mod_fastcgi will be able to talk to it.

A decent FastCGI server may implement a pre-forking FastCGI server. That is, after initialization, a number of children are forked, and they process incoming requests. Just like the classic Apache worker model.

Some of the benefits of FastCGI over classic CGI:

  • The J interpreter is loaded only once on start-up, not once on every request.
  • Likewise, your application is only loaded / parsed once.
  • If your application needs to initialize (load config files, pre-cache things), you can do this once, on start-up, before you call serve()
  • Virtually zero start-up time per request means a huge improvement for request latency.

References:

J Interpreter

For most purposes, the jconsole should suffice for FastCGI, but the full J system can also be used if required.

FastCGI Server

A FastCGI server is a socket server that works togther with HTTP server. You need at least a script with definitions to read the FastCGI parameters and create the required FastCGI output. What else is needed depends on your application. This can include the J standard libraries.

A minimal FastCGI server is Scripts/FastCGI and SCGI Server fscgidemo.ijs. This is not a standalone script, and can be used for testing only.

For IDE, open and run this script. For jconsole, use dos command or shell to type

./jconsole fscgidemo.ijs

The server does not exit after processing incoming requests, the J session remains alive indefinitely. Only FastCGI server running under win32 with c++ frontend can respond to user command. For all other cases, it can be stopped by requesting the url

http://localhost/fcgi/bye.ijs

in the browser.

FastCGI Server Mode

Depending on HTTP servers, there are three ways to run your application under FastCGI:

  • external (standalone)
  • static
  • dynamic

These terms may be misleading because all of them are external to HTTP server. They run as a separate process, not as dynamic link or shared library. Taking the example of Apache with mod_fastcgi.so

Standalone server mode

In external (standalone) mode the FastCGI server runs as a standalone server and accepts connections from a web server. The FastCGI server can be on the same machine as the web server, on a remote machine, or even on multiple remote machines. Advantages of this method include running a FastCGI server as a different user than the web server, and the ability to set up a scalable server farm.

Static mode

This happens at Apache startup time. In this case you do not start your FastCGI server -- that is done by Apache.

Dynamic mode

In FastCGI dynamic mode, Apache will run your FastCGI server on demand, typically by requesting a file with a specific extension (e.g. .fcgi). ISPs often use this type of setup to provide FastCGI support to many customers.

The above mentioned demo FastCGI server in J is a standalone server.

Permissions

A FastCGI server runs as a separate process and it can (usually if under Linux) run under a different user id. File permissions should allow the FastCGI server to run the J interpreter, and read the scripts. Scripts do not need execution permission.

HTTP Servers that supporting FastCGI

There are a number of HTTP servers supporting FastCGI, eg.

A longer list can be found in Comparison of web servers.

Apache Configuration (Win32)

It needs to add information for module mod_fastcgi.so into the httpd.conf

Edit Apache's config file: conf/httpd.conf

Add this line immediately after the the LoadModule of mod_rewrite (make sure mod_rewrite is uncommented):

LoadModule fastcgi_module modules/mod_fastcgi.so

For Apache1 only, add the following immediately after the AddModule of mod_rewrite:

AddModule mod_fastcgi.c

Apache2 doesn’t use AddModule.

where all the rest of the LoadModules are. And then this at the end:

Alias /fcgi "c:/temp/fcgi"
<Location /fcgi>
    AllowOverride none
    Order allow,deny
    Allow from all
</Location>
FastCgiExternalServer "c:/temp/fcgi" -host 127.0.0.1:8999

Remember to create the directory "c:\temp" if not present. However the subdirectoy fcgi is not needed.

In this example, all request to directory /fcgi in HTTP server's document root will be routed to FastCGI server at IP address 127.0.0.1 port 8999. So that the FastCGI server should listen to port 8999 of IP address 127.0.0.1.

There is a FastCGIHandler option that coupled with a LocationMatch tag to enable/disable FastCGI handling or for virtual hosting.

The hardest part is to get the file mod_fastcgi.so itself because the mod_fastcgi module is not come with the Apache offical release. There is pre-built binary from third parties, download it and place the mod_fastcgi.so in your Apache's modules dir.

References:

Apache Configuration (Linux)

This has been tested on Apache/2.0.55 (Ubuntu).

The file mod_fastcgi.so is not available from Linux distribution or package manager's repository, so that it has to be built from source.

  • Install development headers for Apache2 from package manager.
  • Download source code for mod_fastcgi
  • Next save the following (you need sudo to do this.)
LoadModule fastcgi_module /usr/lib/apache2/modules/mod_fastcgi.so
Alias /fcgi /tmp/fcgi
<Location /fcgi>
    AllowOverride none
    Order allow,deny
    Allow from all
</Location>
FastCgiExternalServer /tmp/fcgi -host 127.0.0.1:8999
as
/etc/apache2/mods-enabled/fcgi.conf
  • Untar FastCGI source and cd to its mod_fastcgi_dir directory,
$ tar -xvzf mod_fastcgi-SNAP-0404142202.tar.gz
$ cd <mod_fastcgi_dir>
  • Read and follow the installation guide INSTALL.AP2
$ cp Makefile.AP2 Makefile
$ make top_dir=/usr/share/apache2
$ sudo make top_dir=/usr/share/apache2 install
This will compile mod_fastcgi.so and move it to /usr/lib/apache2/modules/.
  • Finally test config and restart the Apache server.
$ apache2ctl -t
$ sudo /etc/init.d/apache2 restart

References:

Lighttpd Configuration

Since FastCGI is built-in, you’ll only need to tell Lighttpd how to connect to your FastCGI server. All you need to do is point lighttpd at one port.

Linux : edit the file lighttpd.conf (actually I use gedit because I don't know how to use vi)

$ sudo vi /etc/lighttpd/lighttpd.conf

Win32 : use notepad or other text editor to open the file

c:\lighttpd\etc\lighttpd.conf

Make sure you have mod_fastcgi mentioned in the modules:

## modules to load
# at least mod_access and mod_accesslog should be loaded
# all other module should only be loaded if really neccesary
# - saves some time
# - saves memory
server.modules              = (
#                               "mod_rewrite",
#                               "mod_redirect",
#                               "mod_alias",
                                "mod_access",
#                               "mod_cml",
#                               "mod_trigger_b4_dl",
#                               "mod_auth",
#                               "mod_status",
#                               "mod_setenv",
                                "mod_fastcgi",
#                               "mod_proxy",
#                               "mod_simple_vhost",
#                               "mod_evhost",
#                               "mod_userdir",
#                               "mod_cgi",
#                               "mod_scgi",
#                               "mod_compress",
#                               "mod_ssi",
#                               "mod_usertrack",
#                               "mod_expire",
#                               "mod_secdownload",
#                               "mod_rrdtool",
                                "mod_accesslog" )

Next you have to tell Lighttpd to route requests to FastCGI server and not to check for local. Add the following to the config file.

#### fastcgi module
## read fastcgi.txt for more info
## for PHP don't forget to set cgi.fix_pathinfo = 1 in the php.ini
    fastcgi.server = ( "/fcgi/" =>
      (( "host" => "127.0.0.1",
	 "port" => 8999,
         "check-local" => "disable",
         "docroot" => "/" # remote server may use
	                  # it's own docroot
      ))
    )

Save the configuration and close all the files. Restart the lighttpd:

$ sudo /etc/init.d/lighttpd restart

In this example, all request to directory /fcgi in HTTP server's document root will be routed to FastCGI server at IP address 127.0.0.1 port 8999. So that the FastCGI server should listen to port 8999 of IP address 127.0.0.1.

Lighttpd will not check whether requested files actually exist or not because FastCGI may have a different document root or even resides in another computer.

Lighttpd also allow multiple FastCGI servers on the same computer or other computers to do load balancing.

References:

Cherokee Configuration

Again FastCGI is built-in, it is very simple to connect to a FastCGI server.

Linux : edit the file cherokee.conf

$ sudo vi /etc/cherokee/cherokee.conf

Win32 : use notepad or other text editor to open the file

C:\Program Files\Cherokee\cherokee.conf

Add this section at the end:

Directory /fcgi {
   Handler fcgi {
      Server 127.0.0.1:8999
   }
}

Save the configuration and close all the files. Restart the cherokee:

$ sudo /etc/init.d/cherokee restart

References:

Microsoft IIS Configuration

Microsoft releases a collaborative effort to improve PHP performance and stability on IIS. Visit the home for FastCGI on IIS.NET to learn more about FastCGI, PHP, and IIS.

(Current version requires window host script for installation. Please feel free to add IIS specific material here.)

FastCGI script

This is an ordinary J script, not a hash bang script since J interpreter is already running. Execution permission is not needed. It can assume neccesary libraries has been loaded by FastCGI server.

Simple Example

Save the following as test1.ijs

NB. =========================================================
NB. cgitest v. defines html with a timestamp and cgi parameters
cgitest=: 3 : 0
require 'dates'
stdout 'Status: 200 OK', LF
stdout 'Content-type: text/html',LF,LF,'<html><body><pre>',LF
stdout LF,~'external'
stdout LF,~":6!:0''
stdout ,LF,.~":cgiparms''
stdout ,LF,.~":3 4$calendar {. 6!:0 ''
stdout '

</body></html>'

)

cgitest

to your cgi-bin directory eg.

/home/bill/cgi-bin/test1.ijs

ensure that the FastCGI server has read access.

<!> FastCGI server (fscgidemo) assume HOMEDIR=: '/home/bill/cgi-bin' your need to change this line and make sure SKPORT=: 8999 before running the demo.

In Linux, the root directory holding HTTP web page files usually be

/var/www

while in Win32, it usually be the sub-directory htdocs under web server's program root.

Next, save the following as file fcgitest1.html in your web directory:

<html><body>
<form action="/fcgi/test1.ijs" method="get">
<input type=text value="get me" name=tget><br>
<input type="submit" value="Run">
</form></body></html>

also, save the following as file fcgitest2.html in your web directory:

<html><body>
<form action="/fcgi/test2.ijs" method="post">
<input type=text value="get me" name=tget><br>
<input type="submit" value="Run">
</form></body></html>

Note that the use of POST instead of GET, and there is no test2.ijs, it will be handled internally by FastCGI server as a demonstration.

Open these files in your browser, and press the Run button. The resulting display should show the timestamp, and the edit box name and contents:

external
2007 1 5 22 43 12.969
+----+------+
|tget|get me|
+----+------+

If this does not work, you should check that the FastCGI server is running, also check the firewall setting and server log.

<!> Current version of Cherokee has bug that prevent fcgitest1.html to be executed correctly. The bug has been fixed in svn and will be available in the next release.

References


Contributed by Bill Lam