$Id: fastcgi.txt,v 1.1 2004/04/07 09:06:32 weigon Exp $

the FastCGI Interface

Module: 

  mod_fastcgi

Description:

  lighttpd provides an interface to a external programs that 
  support the FastCGI interface. The FastCGI Interface is 
  defined by http://www.fastcgi.com/ and is a 
  platform-indepentant and server independant interface between
  a web-application and a webserver.

  This means that FastCGI programs that run with the Apache 
  Webserver will run seamlessly with lighttpd and vice versa.


  FastCGI
  
  FastCGI is removes a lot of the limitations of CGI programs. 
  CGI programs have the problem that they have to be restarted 
  by the webserver for every request which leads to really bad 
  performance values.

  FastCGI removes this limitation by keeping the process running 
  and handling the requests by this always running process. This 
  removes the time used for the fork() and the overall startup 
  and cleanup time which is neccesary to create and destroy a 
  process.

  While CGI programs communicate to the server over pipes, 
  FastCGI processes use Unix-Domain-Sockets or TCP/IP to talk 
  with the webserver. This gives you the second advantage over 
  simple CGI programs: FastCGI don't have to run on the Webserver
  itself but everywhere in the network. 

  lighttpd takes it a little bit further by providing a internal 
  FastCGI load-balancer which can be used to balance the load 
  over multiple FastCGI Servers. In contrast to other solutions 
  only the FastCGI process has to be on the cluster and not the 
  whole webserver. That gives the FastCGI process more resources
  than a e.g. load-balancer+apache+mod_php solution.

  If you compare FastCGI against a apache+mod_php solution you 
  should note that FastCGI provides additional security as the 
  FastCGI process can be run under different permissions that 
  the webserver and can also live a chroot which might be 
  different than the one the webserver is running in. 
  
  
  Preparing PHP as a FastCGI program

  One of the most important application that has a FastCGI 
  interface is php which can be downloaded from 
  http://www.php.net/ . You have to recompile the php from 
  source to enable the FastCGI interface as it is normally 
  not enabled by default in the distributions.

  If you already have a working installation of PHP on a 
  webserver execute a small script which just contains

  <?php phpinfo(); ?>
  
  and search for the line in that contains the configure call. 
  You can use it as the base for the compilation.

  You have to add three switches to compile PHP with FastCGI
  support 

  $ ./configure \
    --enable-fastcgi \
    --enable-discard-path \
    --enable-force-cgi-redirect \
    ...
    
  --enable-fastcgi enables the FastCGI support in the 
  CGI-Server API which means that all switches to enable 
  APXS or Apache SAPI have to be removed.

  After compilation and installation check that your PHP 
  binary contains FastCGI support by calling:

  $ php -v
  PHP 4.3.3RC2-dev (cgi-fcgi) (built: Oct 19 2003 23:19:17)

  The important part is the (cgi-fcgi).


  Starting a FastCGI-PHP

  For convinience you should use the spawn-php.sh script 
  located in the download area of lighttpd for starting a
  FastCGI-PHP.

  The script has a set of config variables you should take 
  a look at:

  ## ABSOLUTE path to the spawn-fcgi binary
  SPAWNFCGI="/usr/local/sbin/spawn-fcgi"

  ## ABSOLUTE path to the PHP binary
  FCGIPROGRAM="/usr/local/bin/php"

  ## bind to tcp-port on localhost
  FCGIPORT="1026"

  ## number of PHP childs to spawn
  PHP_FCGI_CHILDREN=10

  ## number of request server by a single php-process until
  ## is will be restarted
  PHP_FCGI_MAX_REQUESTS=1000

  ## IP adresses where PHP should access server connections
  ## from
  FCGI_WEB_SERVER_ADDRS="127.0.0.1,192.168.0.1"

  # allowed environment variables sperated by spaces
  ALLOWED_ENV="ORACLE_HOME PATH USER"

  ## if this script is run as root switch to the following user
  USERID=wwwrun
  GROUPID=wwwrun

  If you have set the variables to values that fit to your 
  setup you can start it by calling:

  $ spawn-php.sh
  spawn-fcgi.c.136: child spawned successfully: PID: 6925
  
  If you get "child spawned successfully: PID:" the php 
  processes could be started successfully. You should see them 
  in your processlist:
  
  $ ps ax | grep php
  6925 ?        S      0:00 /usr/local/bin/php
  6928 ?        S      0:00 /usr/local/bin/php
  ...
  
  The number of processes should be PHP_FCGI_CHILDREN + 1. 
  Here the process 6925 is the master of the slaves which 
  handle the work in parallel. Number of parallel workers can 
  be set by PHP_FCGI_CHILDREN. A worker dies automaticly of 
  handling PHP_FCGI_MAX_REQUESTS requests as PHP might have 
  memory leaks.

  If you start the script as user root php processes will be 
  running as the user USERID and group GROUPID to drop the 
  root permissions. Otherwise the php processes will run as 
  the user you started script as.

  As the script might be started from a unknown stage or even 
  directly from the command-line it cleans the environment 
  before starting the processes. ALLOWED_ENV contains all 
  the external environement variables that should be available 
  to the php-process.


Configuration:

  lighttpd provides the FastCGI support via the fastcgi-module 
  (mod_fastcgi) which provides 2 options in the config-file:

  fastcgi.debug
    a value between 0 and 65535 to set the debug-level in the 
    FastCGI module. Currently only 0 and 1 are used. Use 1 to 
    enable some debug output, 0 to disable it.
  
  fastcgi.server
    tell the module where to send FastCGI requests to. Every 
    file-extension can have it own handler. Load-Balancing is 
    done by specifying multiple handles for the same extension.

    structure of fastcgi.server section:
      ( <extension> => 
        ( <handle> => 
          ( "host" => <string> ,
            "port" => <integer> ,
            "mode" => <string>,         # OPTIONAL
	    "docroot" => <string> ,     # OPTIONAL if "mode" 
	                                #   is not "authorizer"
            "check-local" => <string> ) # OPTIONAL
        ), 
        ( <handle> => ... 
        )
      )
    
    <extension> is the file-extension or prefix 
                (if started with "/")
    <handle>    is just a unique handle name
    "host"      is hostname/ip of the FastCGI process
    "port"      is tcp-port on the "host" used by the FastCGI
                process
    "mode"      is the FastCGI protocol mode. 
                Default is "responder", also "authorizer" 
		mode is implemented.
    "docroot"   is optional and is the docroot on the remote 
                host for default "responder" mode. For 
		"authorizer" mode it is MANDATORY and it points 
		to docroot for authorized requests. For security
		reasons it is recommended to keep this docroot
                outside of server.document-root tree.
    "check-local" is optional and may be "enable" (default) or 
                "disable". If enabled the server first check 
		for a file in local server.document-root tree 
		and return 404 (Not Found) if no such file.
                If disabled, the server forward request to 
		FastCGI interface without this check.

    e.g.:
    fastcgi.server = ( ".php" =>
 		       ( "grisu" => 
		         ( 
		           "host" => "192.168.0.2",
		           "port" => 1026
		         )
		       )
		     )

    Example with prefix:
    fastcgi.server = ( "/remote_scripts" =>
   		       ( "fcg" =>
		         (
		           "host" => "192.168.0.3",
		           "port" => 9000,
                           "check-local" => "disable",
                           "docroot" => "/" # remote server may use 
			                    # it's own docroot
		         )
		       )
		     )
		     
    The request http://my.host.com/remote_scripts/test.cgi will
    be forwarded to fastcgi server at 192.168.0.3 and the value
    "/remote_scripts/test.cgi" will be used for the SCRIPT_NAME
    variable. Remote server may prepend it with its own 
    document root. The handling of index files si also the 
    resposibility of remote server for this case.


    Example for "authorizer" mode:
    fastcgi.server = ( "/remote_scripts" =>
 		       ( "auth" =>
		         (
		           "host" => "192.168.0.3",
		           "port" => 9000,
                           "docroot" => "/path_to_private_docs",
                           "mode" => "authorizer"
		         )
		       )
		     )

    Note that if "docroot" is specified then its value will be 
    used in DOCUMENT_ROOT and SCRIPT_FILENAME variables passed
    to FastCGI server.
				

  Skeleton for remote authorizer

  The basic functionality of authorizer is as follows (see
  http://www.fastcgi.com/devkit/doc/fcgi-spec.html, 6.3 for 
  details).

  #include <fcgi_stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  int main () {
    char* p;

    while (FCGI_Accept() >= 0) {   
      /* wait for fastcgi authorizer request */

      printf("Content-type: text/html\r\n");

      if ((p = getenv("QUERY_STRING")) == NULL) ||
           <QUERY_STRING is unauthorized>)
           printf("Status: 403 Forbidden\r\n\r\n");

      else printf("\r\n");  
        /* default Status is 200 - allow access */
    }

    return 0;
  }

  It is possible to use any other variables provided by 
  FastCGI interface for authorization check. Here is only an 
  example.


  Troubleshooting

  fastcgi.debug should be enabled for troubleshooting.

  If you get:

  (fcgi.c.274) connect delayed:  8
  (fcgi.c.289) connect succeeded:  8
  (fcgi.c.745) unexpected end-of-file (perhaps the fastcgi 
     process died):  8

  the fastcgi process accepted the connection but closed it 
  right away. This happens if FCGI_WEB_SERVER_ADDRS doesn't 
  include the host where you are connection from.

  If you get 

  (fcgi.c.274) connect delayed:  7
  (fcgi.c.1107) error: unexpected close of fastcgi connection 
     for /peterp/seite1.php (no fastcgi process on host/port ?)
  (fcgi.c.1015) emergency exit: fastcgi: connection-fd: 5 
     fcgi-fd: 7

  the fastcgi process is not running on the host/port you are 
  connection to. Check your configuration.

  If you get

  (fcgi.c.274) connect delayed:  7
  (fcgi.c.289) connect succeeded:  7

  everything is fine. The connect() call just was delayed a 
  little bit and is completly normal.

