apache / mod-fastcgi

I needed to put up a python3 application on apache but had a python2/mod_python application that I couldn't touch, and since python2/mod_python and python3/mod_wsgi didn't play together (even with mod_wsgi in daemon mode), I used python3 with mod_fastcgi.

## mod_fastcgi implements the fastcgi protocol in apache2; it allows apache to start up and communicate via sockets with applications that service requests as in traditional cgi but that remain running in order to process further requests; this maintains the process-separation of traditional cgi i.e. with the application external to the web server but dramatically increases performance and flexibility

! in fact applications may be started independently of apache and simply left running for apache to communicate with

! using ubuntu 12.04, apache 2.22, python 3.3.5

! links
http://www.fastcgi.com/drupal/node/25 # mod_fastcgi doc
http://www.nongnu.org/fastcgi/ # FastCGI - The Forgotten Treasure

! http://www.apachelounge.com/viewtopic.php?t=4385
"mod_fcgi is NOT a replacement for mod_fastcgi"
i.e. mod_fastcgi sends multiple requests per fastcgi process; mod_fcgid sends only one request per fastcgi process and so must start up multiple processes to handle multiple simultaneous requests; the processes need only be single-threaded

! http://www.fastcgi.com/drupal/node/25
"The FastCGI protocol supports a feature, described in the specificiation as "multiplexing", that allows a single client-server connection to be simultaneously shared by multiple requests. This is not supported. This does not prevent FastCGI applications from supporting multiple simultaneous requests over independent connections. Of course, the application has to be specifically designed to do so by using a threaded or select/poll based server model."
i.e. multiplexing is sending multiple requests over the same socket connection; mod_fastcgi doesn't support multiplexing; however it does support multiple simultaneous socket connections to an application when simultaneous requests are received so a multithreading application is important

## installed libapache2-mod-fastcgi package from ubuntu using apt-get

! libapache2-mod-fastcgi package is a fastcgi module for apache2
! libapache2-mod-fcgid package is an alternative fastcgi module compatible with mod_fastcgi

root@dev:~# apt-get install libapache2-mod-fastcgi
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 55.2 kB of archives.
After this operation, 270 kB of additional disk space will be used.
Get:1 http://nl.archive.ubuntu.com/ubuntu/ precise/multiverse libapache2-mod-fastcgi amd64 2.4.7~0910052141-1 [55.2 kB]
Fetched 55.2 kB in 0s (348 kB/s)                  
Selecting previously unselected package libapache2-mod-fastcgi.
(Reading database ... 91945 files and directories currently installed.)
Unpacking libapache2-mod-fastcgi (from .../libapache2-mod-fastcgi_2.4.7~0910052141-1_amd64.deb) ...
Setting up libapache2-mod-fastcgi (2.4.7~0910052141-1) ...
Enabling module fastcgi.
To activate the new configuration, you need to run:
  service apache2 restart

! file/directories
/var/lib/apache2/fastcgi/dynamic/ # socket files

! no mod_fastcgi status section appears in apache's server_status

! the apache name of mod_fastcgi is fastcgi-script

! default /etc/apache2/mods-available/fastcgi.load

LoadModule fastcgi_module /usr/lib/apache2/modules/mod_fastcgi.so

! default /etc/apache2/mods-available/fastcgi.conf

<IfModule mod_fastcgi.c>
  AddHandler fastcgi-script .fcgi
  #FastCgiWrapper /usr/lib/apache2/suexec
  FastCgiIpcDir /var/lib/apache2/fastcgi

! pstree with mpm worker

├─apache2─┬─2*[apache2]                    # mod_cgid and mod_fastcgi processes
│         └─2*[apache2───26*[{apache2}]]   # main apache processes

## mod_fastcgi configuration is similar to that with cgi; there are no equivalents to ScriptAlias and ScriptAliasMatch so Alias and a Directory with SetHandler and Options ExecCGI are typically used

! nothing prevents fastcgi and cgi from being used together in the same directory via AddHandler directives

! a mod_fastcgi directory requires the ExecCGI option

Alias /cgi-bin/ /usr/lib/cgi-bin/               # aliasing a directory
# or Alias /myapp /usr/lib/cgi-bin/myapp.fcgi   # aliasing a script; path following /myapp in url is passed in envvar PATH_INFO

<Directory /usr/lib/cgi-bin>
        AllowOverride None
        Options ExecCGI
        Order Allow,Deny
        Allow from all
        SetHandler fastcgi-script               # or AddHandler fastcgi-script .fcgi with other AddHandler directives

! FastCgiConfig -maxClassProcesses 1 in the apache server context causes mod_fastcgi to start only one process per application

! FastCgiConfig -autoUpdate in the apache server context causes mod_fastcgi to check the mtime of the application and if it has changed then restart the process

## scripts are run in the usual way i.e. they must be permissioned executable and a #! line is used to specify the interpreter; but the fastcgi protocol differs from the cgi protocol in that it uses a socket rather than standard i/o between the http server and script i.e. between the fastcgi gateway and fastcgi application; this means that cgi scripts can't be used unmodified with fastcgi and it can't be tested simply by writing from the script to stdout

! mod_fastcgi routes stdout and stderr to the apache error log

! python wsgi scripts may make use of flup which is a fastcgi-to-wsgi adapter

! typical hello python wsgi script with #! line and module-level code added to use flup


def application(environ, start_response):
    body = '<html><body><h2>hello world</h2></body></html>'
    status = '200 OK'
    headers = [('Content-Type', 'text/html'), ('Content-Length', str(len(body)))]
    start_response(status, headers)
    return [body]

if __name__ == '__main__':
    from flup.server.fcgi import WSGIServer

! pstree with mpm worker; if multiple applications are in use then each runs in its own interpreter

     ├─apache2─┬─apache2                                   # mod_cgid process
     │         ├─apache2───hello.fcgi───5*[{hello.fcgi}]   # mod_fastcgi processes
     │         └─2*[apache2───26*[{apache2}]]              # main apache processes

     │         ├─apache2─┬─hello.fcgi───5*[{hello.fcgi}]
     │         │         └─hello2.fcgi───5*[{hello2.fcgi}]
     │         └─2*[apache2───26*[{apache2}]]

! apache error log for start of apache with mod_fastcgi, mod_python, and mod_wsgi

[Tue Oct 15 08:11:35 2013] [notice] FastCGI: process manager initialized (pid 15773)
[Tue Oct 15 08:11:35 2013] [error] python_init: Python version mismatch, expected '2.7.2+', found '2.7.3'.
[Tue Oct 15 08:11:35 2013] [error] python_init: Python executable found '/usr/bin/python'.
[Tue Oct 15 08:11:35 2013] [error] python_init: Python path being used '/usr/lib/python2.7/:/usr/lib/python2.7/plat-linux2:/usr/lib/python2.7/lib-tk:/usr/lib/python2.7/lib-old:/usr/lib/python2.7/lib-dynload'.
[Tue Oct 15 08:11:35 2013] [notice] mod_python: Creating 8 session mutexes based on 3 max processes and 25 max threads.
[Tue Oct 15 08:11:35 2013] [notice] mod_python: using mutex_directory /tmp 
[Tue Oct 15 08:11:35 2013] [warn] mod_wsgi: Compiled for Python/2.7.2+.
[Tue Oct 15 08:11:35 2013] [warn] mod_wsgi: Runtime using Python/2.7.3.
[Tue Oct 15 08:11:35 2013] [notice] Apache/2.2.22 (Ubuntu) mod_fastcgi/mod_fastcgi-SNAP-0910052141 mod_python/3.3.1 Python/2.7.3 mod_wsgi/3.3 configured -- resuming normal operations

! start of mod_fastcgi application

[Tue Oct 15 08:11:58 2013] [warn] FastCGI: (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi" started (pid 15966)

! start of mod_fastcgi application with -maxClassProcesses 1

[Tue Oct 15 08:16:29 2013] [warn] FastCGI: scheduled the start of the last (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi" process: reached dynamicMaxClassProcs (1)
[Tue Oct 15 08:16:29 2013] [warn] FastCGI: (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi" started (pid 15866)

! restart of mod_fastcgi application due to -autoUpdate

[Tue Oct 15 08:25:03 2013] [warn] FastCGI: restarting old server "/home/keith/dev/python/testcgi/hello.fcgi" processes, newer version found
[Tue Oct 15 08:25:03 2013] [warn] FastCGI: scheduled the restart of the last (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi" process: reached dynamicMaxClassProcs (1)
[Tue Oct 15 08:25:03 2013] [warn] FastCGI: (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi" (pid 15866) terminated by calling exit with status '0'
[Tue Oct 15 08:25:03 2013] [warn] FastCGI: (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi" restarted (pid 15907)

! mod_fastcgi application without execute permission

[Tue Oct 15 15:28:08 2013] [error] [client] FastCGI: invalid (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi": access for server (uid 33, gid 33) not allowed: execute not allowed

! if an application fails to run for at least min-server-life (30) seconds then the process manager will wait restart-delay (5) seconds before trying again; if the application fails like this three times then its restart-delay will be increased to 600 seconds

[Mon Oct 14 19:45:43 2013] [warn] FastCGI: (dynamic) server "/home/keith/dev/python/testcgi/hello.fcgi" has failed to remain running for 30 seconds given 3 attempts, its restart interval has been backed off to 600 seconds
Currently unrated





RSS / Atom