NSLU2-Linux
view · edit · print · history

FastCGI is a protocol for interfacing between web applications and the web server. Because it offers much better performance than CGI, it is often used to deploy PHP web applications on lightweight web servers that do not have a built-in mod_php.

The example below is on unslung firmware and using optware packages. Whenever you see cat filename, it means you need to use editor to create filename with the corresponding conent, so that when you type cat filename, you will see the following file content.


Install PHP & php-fcgi packages

# ipkg install php php-fcgi
# ipkg install libstdc++ 

A PHP test page

$ cat ~/test-php/info.php
<?php phpinfo(); ?> 

Launch php-fcgi command (remember to add a trailing & to launch in background).

$ /opt/bin/php-fcgi 

Install a web server with FastCGI support

Install lighttpd

# ipkg install lighttpd 

Or, install cherokee

# ipkg install cherokee

Please note cherokee 0.4.31b18 fixed a couple of SCGI/FastCGI problems. Version earlier than this probably does not work.

  • Vikezz: I've made a new guide over at http://unslung.blogspot.com. It will guide you through an installation of the Cherokee 0.7.2 webserver on a slug(unslung).

Configure & launching the web server

cherokee

WARNING: the configuration has changed with Cherokee 0.6.0. Information below is outdated. Configuration instruction for 0.6.1-1 at http://tech.groups.yahoo.com/group/nslu2-linux/message/21403.

This is what I had to do to update from 0.5.6-3 to 0.6.1-2:

  Use the new cherokee.conf file
  Use the new mime.types file
  Use the new S80cherokee file

  Edit /opt/etc/cherokee/cherokee.conf file
    Possible changes
      server!port = 8008	'use the correct port here		
      server!port_tls = 8008	'use the correct port here
      vserver!default!directory_index = index.php,index.html	'use the correct file extensions here
        'I use index.htm as the updates have overwritten the index.html file with a cherokee default one.

Jim

$ cat ~/test-php/cherokee-php.conf 
Port 8082
IPv6 Off
Timeout 60
KeepAlive On
MaxKeepAliveRequests 500
ServerTokens Full
PidFile /home/mylogin/tmp/cherokee.pid
Icons /opt/etc/cherokee/icons.conf
MimeFile /opt/etc/cherokee/mime.types
MimeFile /opt/etc/cherokee/mime.compression.types
Include /opt/etc/cherokee/advanced.conf
Include /opt/etc/cherokee/mods-enabled
Documentroot /home/mylogin/test-php
DirectoryIndex index.html
Extension php, php3, php4, php5 {
  Handler fcgi {
    Server localhost:8002 {
      Env PHP_FCGI_MAX_REQUESTS "4000"
      Env PHP_FCGI_CHILDREN "4"
        Interpreter "/opt/bin/php-fcgi -b 8002"
    }
  }
}

Launch it.

$ /opt/sbin/cherokee -C ~/test-php/cherokee-php.conf 
Cherokee Web Server 0.4.31b18: Listening on port 8083, TLS disabled
 IPv6 disable, using poll, 1024 fds limit, 5 threads, 204 fds in each
 standard scheduling policy

Or lighttpd

$ cat ~/test-php/lighttpd-php.conf 
server.port                = 8081
server.modules              = (
                                "mod_access",
                                "mod_fastcgi",
                                "mod_accesslog" )
server.document-root        = "/home/mylogin/test-php"
server.errorlog             = "/home/mylogin/test-php/error.log"
accesslog.filename          = "/home/mylogin/test-php/access.log"
index-file.names            = ( "index.php", "index.html",
                                "index.htm", "default.htm" )
mimetype.assign             = (
  ".pdf"          =>      "application/pdf",
  ".sig"          =>      "application/pgp-signature",
  ".spl"          =>      "application/futuresplash",
  ".class"        =>      "application/octet-stream",
  ".ps"           =>      "application/postscript",
  ".torrent"      =>      "application/x-bittorrent",
  ".dvi"          =>      "application/x-dvi",
  ".gz"           =>      "application/x-gzip",
  ".pac"          =>      "application/x-ns-proxy-autoconfig",
  ".swf"          =>      "application/x-shockwave-flash",
  ".tar.gz"       =>      "application/x-tgz",
  ".tgz"          =>      "application/x-tgz",
  ".tar"          =>      "application/x-tar",
  ".zip"          =>      "application/zip",
  ".mp3"          =>      "audio/mpeg",
  ".m3u"          =>      "audio/x-mpegurl",
  ".wma"          =>      "audio/x-ms-wma",
  ".wax"          =>      "audio/x-ms-wax",
  ".ogg"          =>      "application/ogg",
  ".wav"          =>      "audio/x-wav",
  ".gif"          =>      "image/gif",
  ".jpg"          =>      "image/jpeg",
  ".jpeg"         =>      "image/jpeg",
  ".png"          =>      "image/png",
  ".xbm"          =>      "image/x-xbitmap",
  ".xpm"          =>      "image/x-xpixmap",
  ".xwd"          =>      "image/x-xwindowdump",
  ".css"          =>      "text/css",
  ".html"         =>      "text/html",
  ".htm"          =>      "text/html",
  ".js"           =>      "text/javascript",
  ".asc"          =>      "text/plain",
  ".c"            =>      "text/plain",
  ".cpp"          =>      "text/plain",
  ".log"          =>      "text/plain",
  ".conf"         =>      "text/plain",
  ".text"         =>      "text/plain",
  ".txt"          =>      "text/plain",
  ".dtd"          =>      "text/xml",
  ".xml"          =>      "text/xml",
  ".mpeg"         =>      "video/mpeg",
  ".mpg"          =>      "video/mpeg",
  ".mov"          =>      "video/quicktime",
  ".qt"           =>      "video/quicktime",
  ".avi"          =>      "video/x-msvideo",
  ".asf"          =>      "video/x-ms-asf",
  ".asx"          =>      "video/x-ms-asf",
  ".wmv"          =>      "video/x-ms-wmv",
  ".bz2"          =>      "application/x-bzip",
  ".tbz"          =>      "application/x-bzip-compressed-tar",
  ".tar.bz2"      =>      "application/x-bzip-compressed-tar"
 )
fastcgi.server    = ( ".php" =>
                      ( "localhost" =>
                        (
                          "socket" => "/tmp/php-fcgi.sock",
                          "bin-path" => "/opt/bin/php-fcgi",
                          "bin-environment" => (
                            "PHP_FCGI_CHILDREN" => "4",
                            "PHP_FCGI_MAX_REQUESTS" => "4000"
                               )
                             )
                           )
                        )

The current version of php-fcgi creates the fastcgi.server variables in /opt/etc/lighttpd/conf.d/10-php-fcgi.conf so if that file is included you will get a "Duplicate config variable in conditional" from lighty

Launch it.

$ /opt/sbin/lighttpd -D -f ~/test-php/lighttpd-php.conf 

Test

Here I'm using w3m as web browser, you can also use elinks, or any graphic browser on a different machine (adjust the URL correspondingly).

$ w3m -dump http://localhost:8081/info.php | less 
$ w3m -dump http://localhost:8082/info.php | less 

Note:
If using the default installation parameters the Server Root is on /opt/share/www, and not in /opt/share/www/lighthttp. So your first php test files should be located on the prior directory and not the former.


References:


Up and Running

Let other people know that you successfully use the above procedure to run PHP apps:

  • Brian.Zhou - lighttpd and cherokee optware ipkg on TurboSlug, simple test pages
  • Janne5011 - cherokee,php php-fcgi, Unslung 6.8. I simply replaced my cherokee.conf with the provided above and wrote "/opt/sbin/cherokee -C". Easy =)
  • RobHam - cherokee, php php-fcgi, Unslung 5.5 and Mysql and Imagemagik needed to run Gallery2. My experience is that web pages seem to load very slowly when running php-fcgi in fcgi mode as described above so have reverted back to plane cgi mode. Some changes are needed to the relevant part of the cherokee config script. Running in cgi mode will allow the php-fcgi executable to be automaticaly removed from memory when not needed hence freeing up memory for other program tasks.
Extension php, php3, php4, php5 {
        Handler phpcgi {
                        Interpreter /opt/bin/php-fcgi 
        }
}

It is also possible to run the php-fcgi module in plane cgi mode with Lighttpd. Just add ".php" => "/opt/bin/php-fcgi" to the relevant section of the configuration file as shown below.

cgi.assign                 = ( ".pl"  => "/opt/bin/perl",
                               ".php" => "/opt/bin/php-fcgi",
                               ".cgi" => "/opt/bin/perl" )
}
  • rvanderh3 unslung 6.8, cherokee, php/php-fcgi/php-mysql 5.1.4.1. I had some trouble to get php-cfgi to work. First of all I mixed an older version of php (5.0.x) with php-fcgi and php-mysql (5.1.4.1) which causes php not accepting mysql code. The code of cherokee.conf above didn't work out for me. Thanks to Janne5011 I found out that I had to leave the original untouched and put the next code into /opt/etc/cherokee/sites-available in stead. I was glad I get php en mysql to work this way. But it still is very slow, although (much ?) quicker then under apache.
Extension php, php3, php4, php5 {
  Handler fcgi {
     Server localhost:8002 {
        Env PHP_FCGI_MAX_REQUESTS "4000"
        Env PHP_FCGI_CHILDREN "4"
        Interpreter "/opt/bin/php-fcgi -b 8002"
     }
  }
}
  • Crazyman - I use: Unslung 6.8, php/php-fcgi 5.2.0, SQLite and Lighttpd 1.4.13. Works like a charm with the config file from above!
  • Prupertplum, I found that the hint from Rob was very usefull, plus, I also had to do the following:

Edit the configuration file: cherokee.conf in /opt/etc/cherokee so that the very end of the file reads:

Include /opt/etc/cherokee/sites-enabled/default

This finally got me from the 200 OK error to getting php files to run, yahay!

  • lighttpd-1.4.18ssl + php-fcgi 5.2.4 with eAccelerator v0.9.5.2 works well for me. However, even though i use fcgi_children 4 as above, i get numerous instances of php-fcgi in ps (size 21348!). My current solution is to use the externally spawned way as outlined below. (I just used user and group nobody, which is also what is used in lighttpd.conf. Only don't forget to chmod a+w your lighttpd logfiles also.) With PHP_FCGI_CHILDREN=2 this results in only 3 processes consuming my system memory. Will have to see if this compares well against using apache.

Lighttpd with externally spawned PHP-FCGI

The current version of Lighttpd 1.4.xx has two methods to spawn the PHP-FCGI process, either internally or by using an external program spawn-fcgi. Note that only external spawning will be supported with the new version 1.5.xx when it is eventually released.

There are two steps needed to use externally spawned PHP-FCGI.

Firstly the Lighttpd config file needs to be amended as follows :-

 
fastcgi.server = ( ".php" =>
                   ( "localhost" =>
                     ( "socket" => "/tmp/php-fcgi.sock",
                       "max-procs" => 1
                      )
                    )
                  )

Next, a start up script is needed to externally spawn the PHP-FCGI processes. The following script is based on one supplied with Lighttpd spawn-php.sh. Create an empty file using touch /opt/etc/init.d/S79php-fcgi then flag the file chmod 755 /opt/etc/init.d/S79php-fcgi

Add the following script section to the file using a Linux text editor.

 
#!/bin/sh
# /opt/etc/init.d/S79php-fcgi
#
# NSLU2 spawn-fcgi script for lighttpd
#
## ABSOLUTE path to the spawn-fcgi binary
SPAWNFCGI="/opt/bin/spawn-fcgi"

## ABSOLUTE path to the PHP-FCGI binary
FCGIPROGRAM="/opt/bin/php-fcgi"

## ABSOLUTE path and name of PID-file for spawed process
FCGIPID="/opt/var/run/php-fcgi.pid"

## TCP port or socket to bind to
FCGISOCKET="/tmp/php-fcgi.sock"
# FCGIPORT="1026"

## number of PHP children to spawn (min 2)
PHP_FCGI_CHILDREN=2

## maximum number of requests a single PHP process can serve before it is restarted
PHP_FCGI_MAX_REQUESTS=250

## IP addresses from which PHP should access server connections
FCGI_WEB_SERVER_ADDRS="127.0.0.1,192.168.1.77"

## Allowed environment variables, separated by spaces
ALLOWED_ENV="PATH SHELL USER"

## user and group to run PHP-FCGI
USERID=www
GROUPID=everyone

################## no config below this line

if [ -z "$1" ] ; then
  case `echo "$0" | /bin/sed 's:^.*/\(.*\):\1:g'` in
    S??*) rc="start" ;;
    K??*) rc="stop" ;;
    *) rc="usage" ;;
  esac
else
  rc="$1"
fi

case "$rc" in
  start)
    echo -n "Starting PHP-FCGI: "
    export PHP_FCGI_MAX_REQUESTS
    export FCGI_WEB_SERVER_ADDRS
    ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS"
    if [ -n "$FCGISOCKET" ]; then
      EX="$SPAWNFCGI -s $FCGISOCKET -f $FCGIPROGRAM -P $FCGIPID -C $PHP_FCGI_CHILDREN -u $USERID -g $GROUPID"
    elif [ -n "$FCGIPORT" ]; then
      EX="$SPAWNFCGI -p $FCGIPORT -f $FCGIPROGRAM -P $FCGIPID -C $PHP_FCGI_CHILDREN -u $USERID -g $GROUPID"
    else
      echo "- ERROR - socket or port must be specified!"
      exit 0
    fi
    E=
    for i in $ALLOWED_ENV; do
      eval "x=\$$i"
      E="$E $i=$x"
    done
    env - $E $EX
    echo ok
      ;;
  stop)
    if [ -n "`pidof php-fcgi`" ]; then
      echo -n "Stopping PHP-FCGI: "
      killall php-fcgi 2> /dev/null
      echo ok
    fi
      ;;
  restart)
    "$0" stop
    sleep 3
    "$0" start
      ;;
  *)  
    echo "Usage: $0 (start|stop|restart|usage)"
      ;;
esac

Notes :-

The PHP_FCGI_MAX_REQUESTS variable is deliberately set to a small value to improve server performance. Users may need to increase this a little but high values should be avoided.

The spawned PHP-FCGI process should run with the same USER and GROUP as your web server (the use of USER/GROUP root will not work with externally spawned PHP-FCGI ) . The script assumes that a user www has been created for this purpose. Note that the owner and group settings of the web page files serviced by your web server will probably need to be set to the same using a command similar to chown -R www:everyone /opt/share/www

The max-procs setting can be increased to run more server instances if needed. The PHP_FCGI_CHILDREN setting should also be increased to max-procs + 1.

RobHam - March 2007


''I am trying to set this up right now but can not get it working. i created the php-test page but when i then launch php-fcgi nothing happens anymore i need to ctrl-c to get back to my promt, just running info.php on the slug gives me this error: ./info.php: ./info.php: 1: Syntax error: "(" unexpected''

anyone can help me?
i am really new at this and feel totally lost

Patrick February 2008

-- Please use the mailing list to report problems and ask for help.


Certain Lighttpd versions (I'm using 1.4.18-3) have a bug when trying to access files >512kb it is documented here http://trac.lighttpd.net/trac/ticket/759

It basically says to add the following line to lighttpd.conf and restart the web server.

server.network-backend = "write"

I earlier tried running php with AppWeb? and Thttpd with no luck. Using Unslung 6.8 I installed Lighttpd/FCGI using the instructions above. The only change being that I moved the log files out of the webserver dir for security

I have added this php script: http://phpshow.panmental.de as a lazy way to post photos online without creating thumbs.

The performance is acceptable given the tiny footprint.
JBrown? March 2008

On DD-WRT it needs server.event-handler = "poll" in /opt/etc/lighttpd/lighttpd.conf

The latest package writes a config without it and fails /opt/sbin/lighttpd -f /opt/etc/lighttpd/lighttpd.conf -D

 fdevent_linux_sysepoll.c.131: epoll_create failed (Function not implemented), try to set server.event-handler = "poll" or "select"