123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- =====================
- the FastCGI Interface
- =====================
- -------------------
- Module: mod_fastcgi
- -------------------
- :Author: Jan Kneschke
- :Date: $Date: 2004/11/03 22:26:05 $
- :Revision: $Revision: 1.3 $
- :abstract:
- The FastCGI interface is the fastest and most secure way
- to interface external process-handlers like Perl, PHP and
- your self-written applications.
- .. meta::
- :keywords: lighttpd, FastCGI
- .. contents:: Table of Contents
- 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-independent and server independent 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 necessary 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.
- Options
- =======
- 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.map-extensions
- map multiple extensions to the same fastcgi server
- Example: ::
- fastcgi.map-extensions = ( ".php3" => ".php" )
- 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> =>
- (
- ( "host" => <string> ,
- "port" => <integer> ,
- "socket" => <string>, # either socket
- # or host+port
- "bin-path" => <string>, # OPTIONAL
- "bin-environment" => <array>, # OPTIONAL
- "bin-copy-environment" => <array>, # OPTIONAL
- "mode" => <string>, # OPTIONAL
- "docroot" => <string> , # OPTIONAL if "mode"
- # is not "authorizer"
- "check-local" => <string>, # OPTIONAL
- "max-procs" => <integer>, # OPTIONAL
- "broken-scriptfilename" => <boolean>, # OPTIONAL
- "disable-time" => <integer>, # optional
- "x-sendfile" => <boolean>, # optional (replaces "allow-x-send-file")
- "x-sendfile-docroot" => <boolean>, # optional
- "kill-signal" => <integer>, # OPTIONAL
- "fix-root-scriptname" => <boolean>,
- # OPTIONAL
- ( "host" => ...
- )
- )
- )
- :<extension>: is the file-extension or prefix
- (if started with "/")
- :"host": is hostname/ip of the FastCGI process
- :"port": is tcp-port on the "host" used by the FastCGI
- process
- :"bin-path": path to the local FastCGI binary which should be
- started if no local FastCGI is running
- :"socket": path to the unix-domain socket
- :"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.
- :"broken-scriptfilename": breaks SCRIPT_FILENAME in a wat that
- PHP can extract PATH_INFO from it (default: disabled)
- :"disable-time": time to wait before a disabled backend is checked
- again
- :"x-sendfile": controls if X-Sendfile backend response header is allowed
- (deprecated headers: X-Sendfile2 and X-LIGHTTPD-send-file)
- ("x-sendfile" replaces "allow-x-sendfile")
- :"x-sendfile-docroot": list of directory trees permitted with X-Sendfile
- :"fix-root-scriptname": fix broken path-info split for "/" extension ("prefix")
- If bin-path is set:
- :"max-procs": the upper limit of the processes to start
- :"bin-environment": put an entry into the environment of
- the started process
- :"bin-copy-environement": clean up the environment and copy
- only the specified entries into the fresh
- environment of the spawn process
- :"kill-signal": signal to terminate the FastCGI process with,
- defaults to SIGTERM
- Examples
- --------
- Multiple extensions for the same host ::
- fastcgi.server = ( ".php" =>
- (( "host" => "127.0.0.1",
- "port" => 1026,
- "bin-path" => "/usr/local/bin/php"
- )),
- ".php4" =>
- (( "host" => "127.0.0.1",
- "port" => 1026
- ))
- )
- Example with prefix: ::
- fastcgi.server = ( "/remote_scripts/" =>
- (( "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 is also the
- responsibility of remote server for this case.
- In the case that the prefix is not terminated with a slash
- the prefix will be handled as file and /test.cgi would become
- a PATH_INFO instead of part of SCRIPT_NAME.
- Example for "authorizer" mode: ::
- fastcgi.server = ( "/remote_scripts/" =>
- (( "host" => "10.0.0.2",
- "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.
- Load-Balancing
- ==============
- The FastCGI plugin provides automatically a load-balancing between
- multiple FastCGI servers. ::
- fastcgi.server = ( ".php" =>
- (( "host" => "10.0.0.2", "port" => 1030 ),
- ( "host" => "10.0.0.3", "port" => 1030 ))
- )
- To understand how the load-balancing works you can enable the
- fastcgi.debug option and will get a similar output as here: ::
- proc: 127.0.0.1 1031 1 1 1 31454
- proc: 127.0.0.1 1028 1 1 1 31442
- proc: 127.0.0.1 1030 1 1 1 31449
- proc: 127.0.0.1 1029 1 1 2 31447
- proc: 127.0.0.1 1026 1 1 2 31438
- got proc: 34 31454
- release proc: 40 31438
- proc: 127.0.0.1 1026 1 1 1 31438
- proc: 127.0.0.1 1028 1 1 1 31442
- proc: 127.0.0.1 1030 1 1 1 31449
- proc: 127.0.0.1 1031 1 1 2 31454
- proc: 127.0.0.1 1029 1 1 2 31447
- Even if this for multiple FastCGI children on the local machine
- the following explanation is valid for remote connections too.
- The output shows:
- - IP, port, unix-socket (is empty here)
- - is-local, state (0 - unset, 1 - running, ... )
- - active connections (load)
- - PID
- As you can see the list is always sorted by the load field.
- Whenever a new connection is requested, the first entry (the one
- with the lowest load) is selected, the load is increased (got proc: ...)
- and the list is sorted again.
- If a FastCGI request is done or the connection is dropped, the load on the
- FastCGI proc decreases and the list is sorted again (release proc: ...)
- This behaviour is very light-weight in code and still very efficient
- as it keeps the fastcgi-servers equally loaded even if they have different
- CPUs.
- Adaptive Process Spawning
- =========================
- .. note:: This feature is disabled in 1.3.14 again. min-procs is
- ignored in that release
- Starting with 1.3.8 lighttpd can spawn processes on demand if
- a bin-path is specified and the FastCGI process runs locally.
- If you want to have a least one FastCGI process running and
- more of the number of requests increases you can use min-procs
- and max-procs.
- A new process is spawned as soon as the average number of
- requests waiting to be handle by a single process increases the
- max-load-per-proc setting.
- The idle-timeout specifies how long a fastcgi-process should wait
- for a new request before it kills itself.
- Example
- -------
- ::
- fastcgi.server = ( ".php" =>
- (( "socket" => "/tmp/php.socket",
- "bin-path" => "/usr/local/bin/php",
- "min-procs" => 1,
- "max-procs" => 32,
- "max-load-per-proc" => 4,
- "idle-timeout" => 20
- ))
- )
- Disabling Adaptive Spawning
- ---------------------------
- Adaptive Spawning is a quite new feature and it might misbehave
- for your setup. There are several ways to control how the spawning
- is done:
- 1. ``"max-load-per-proc" => 1``
- if that works for you, great.
- 2. If not set ``min-procs == max-procs``.
- 3. For PHP you can also use: ::
- $ PHP_FCGI_CHILDREN=384 ./lighttpd -f ./lighttpd.conf
- fastcgi.server = ( ".php" =>
- (( "socket" => "/tmp/php.socket",
- "bin-path" => "/usr/local/bin/php",
- "min-procs" => 1,
- "max-procs" => 1,
- "max-load-per-proc" => 4,
- "idle-timeout" => 20
- ))
- )
- It will create one socket and let's PHP create the 384 processes itself.
- 4. If you don't want lighttpd to manage the fastcgi processes, remove the
- bin-path and use spawn-fcgi to spawn them itself.
- FastCGI and Programming Languages
- =================================
- 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 remove all occurrences of `--with-apxs`, `--with-apxs2`
- and the like which would build PHP with Apache support. Add the
- next three switches to compile PHP with FastCGI support::
- $ ./configure \
- --enable-fastcgi \
- --enable-force-cgi-redirect \
- ...
- 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
- ----------------------
- Starting with version 1.3.6 lighttpd can spawn the FastCGI
- processes locally itself if necessary: ::
- fastcgi.server = ( ".php" =>
- (( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php"
- ))
- )
- PHP provides 2 special environment variables which control the number of
- spawned works under the control of a single watching process
- (PHP_FCGI_CHILDREN) and the number of requests what a single worker
- handles before it kills itself. ::
- fastcgi.server = ( ".php" =>
- (( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php",
- "bin-environment" => (
- "PHP_FCGI_CHILDREN" => "16",
- "PHP_FCGI_MAX_REQUESTS" => "10000"
- )
- ))
- )
- To increase the security of the started process you should only pass
- the necessary environment variables to the FastCGI process. ::
- fastcgi.server = ( ".php" =>
- (( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php",
- "bin-environment" => (
- "PHP_FCGI_CHILDREN" => "16",
- "PHP_FCGI_MAX_REQUESTS" => "10000" ),
- "bin-copy-environment" => (
- "PATH", "SHELL", "USER" )
- ))
- )
- Configuring PHP
- ---------------
- If you want to use PATH_INFO and PHP_SELF in you PHP scripts you have to
- configure php and lighttpd. The php.ini needs the option: ::
- cgi.fix_pathinfo = 1
- and the option ``broken-scriptfilename`` in your fastcgi.server config: ::
- fastcgi.server = ( ".php" =>
- (( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php",
- "bin-environment" => (
- "PHP_FCGI_CHILDREN" => "16",
- "PHP_FCGI_MAX_REQUESTS" => "10000" ),
- "bin-copy-environment" => (
- "PATH", "SHELL", "USER" ),
- "broken-scriptfilename" => "enable"
- ))
- )
- Why this ? the ``cgi.fix_pathinfo = 0`` would give you a working ``PATH_INFO``
- but no ``PHP_SELF``. If you enable it, it turns around. To fix the
- ``PATH_INFO`` `--enable-discard-path` needs a SCRIPT_FILENAME which is against the CGI spec, a
- broken-scriptfilename. With ``cgi.fix_pathinfo = 1`` in php.ini and
- ``broken-scriptfilename => "enable"`` you get both.
- External Spawning
- -----------------
- Spawning FastCGI processes directly in the webserver has some
- disadvantages like
- - FastCGI process can only run locally
- - has the same permissions as the webserver
- - has the same base-dir as the webserver
- As soon as you are using a separate FastCGI Server to
- take off some load from the webserver you have to control
- the FastCGI process by a external program like spawn-fcgi.
- spawn-fcgi is used to start a FastCGI process in its own
- environment and set the user-id, group-id and change to
- another root-directory (chroot).
- For convenience a wrapper script should be used which takes
- care of all the necessary option. Such a script in included
- in the lighttpd distribution and is call spawn-php.sh.
- 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"
- ## bind to unix domain socket
- # FCGISOCKET="/tmp/php.sock"
- ## number of PHP children 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 addresses 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 automatically 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 environment variables that should be available
- to the php-process.
- Perl
- ----
- For Perl you have to install the FCGI module from CPAN.
- 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 completely normal.
|