One of the things us ex-Apache httpd or ex-Lighttpd users have to get used to when installing nginx is how there isn't built-in FastCGI support for process spawning. While these means nginx is more lightweight and faster, it does mean that you have to manage your FastCGI processes yourself.

Having just upgraded to Ubuntu Feisty Fawn, I set to installing nginx and tried to get WordPress (which needs PHP, of course) running on it. Thanks to the new nginx package in the Feisty universe repository, getting nginx up and PHP (CGI version) and running is really straightforward. There're lots of tutorials to help you out as well.

So that's that. The part that bugged me though, was how the tutorials always provided a script to start your PHP FastCGI processes, but never provided a way to ensure your FastCGI processes started up on a reboot (i.e. an init script). Once again, Google doesn't disappoint, turning up this php-cgi init script. Tweak the init script a little, put it in /etc/init.d/php-fastcgi, sudo chmod +x /etc/init.d/php-fastcgi, run sudo update-rc.d php-fastcgi defaults and place the configuration for the script in /etc/default/php-fastcgi, and you're done. You now have a PHP FastCGI init script that spawns and kills your PHP FastCGI processes.

Note: Lighttpd does come with a spawn-fcgi binary that does the same, but I'm having trouble finding a suitable init script for spawn-fcgi (only the Gentoo emerge seems to have the init script). Still, this script works and I didn't really want to install lightty on my starving VPS.

The init script: /etc/init.d/php-fastcgi

#! /bin/sh
### BEGIN INIT INFO
# Provides:          php-fastcgi
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start and stop php-cgi in external FASTCGI mode
# Description:       Start and stop php-cgi in external FASTCGI mode
### END INIT INFO

Author: Kurt Zankl <[EMAIL PROTECTED]>

Do NOT "set -e"

PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="php-cgi in external FASTCGI mode" NAME=php-fastcgi DAEMON=/usr/bin/php-cgi PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME PHP_CONFIG_FILE=/etc/php5/cgi/php.ini

Exit if the package is not installed

[ -x "$DAEMON" ] || exit 0

Read configuration variable file if it is present

[ -r /etc/default/$NAME ] && . /etc/default/$NAME

Load the VERBOSE setting and other rcS variables

. /lib/init/vars.sh

Define LSB log_* functions.

Depend on lsb-base (>= 3.0-6) to ensure that this file is present.

. /lib/lsb/init-functions

If the daemon is not enabled, give the user a warning and then exit,

unless we are stopping the daemon

if [ "$START" != "yes" -a "$1" != "stop" ]; then log_warning_msg "To enable $NAME, edit /etc/default/$NAME and set START=yes" exit 0 fi

Process configuration

export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS DAEMON_ARGS="-q -b $FCGI_HOST:$FCGI_PORT -c $PHP_CONFIG_FILE"

do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null
|| return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON
--background --make-pidfile --chuid $EXEC_AS_USER --startas $DAEMON --
$DAEMON_ARGS
|| return 2 }

do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE > /dev/null # --name $DAEMON RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2 exit 3 ;; esac

Config file for init script (the init script looks for this): /etc/default/php-fastcgi

START=yes

Which user runs PHP? (default: www-data)

EXEC_AS_USER=www-data

Host and TCP port for FASTCGI-Listener (default: localhost:9000)

FCGI_HOST=localhost FCGI_PORT=9000

Environment variables, which are processed by PHP

PHP_FCGI_CHILDREN=4 PHP_FCGI_MAX_REQUESTS=1000

nginx config file: /etc/nginx/nginx.conf

location ~ \.php$ {
  fastcgi_pass   127.0.0.1:9000;
  fastcgi_index  index.php;
  fastcgi_param  SCRIPT_FILENAME  /var/www/chuyeow.wtf$fastcgi_script_name;
  include        /etc/nginx/fastcgi.conf;
}

My fastcgi.conf file (I'm not sure I need everything here...)

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx;

fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name;

PHP only, required if PHP was built with --enable-force-cgi-redirect

fastcgi_param REDIRECT_STATUS 200;