I had a problem with Lighttpd and PHP on the default Gentoo install. The configuration that comes with Gentoo, and the “official recommendation” use bin-ath in the mod_fastcgi to point to PHP’s CGI executable.

For example,

fastcgi.server = (
    ".php" => (
        "localhost" => (
            "bin-path"  => "/usr/bin/php-cgi",
            "host" => "127.0.0.1",
            "port" => 1026
        )
    )
)

When lighttpd starts, lighttpd process itself will spawn multiple php-cgi processes, and communicate with them on port 1026 using the FastCGI protocol. Whenever a PHP script needs to be executed, one of spawned php-cgi child will take over the execution.

It is all fine — until the restart time.

There are some issues with lighttpd’s restarting/reloading. First of all, in my experience lighttpd does not always handle reloading properly via the standard SIGHUP. The init script on Gentoo nor implemented “reload” — logrotate script basically relies on the service to restart (Update: logrotate is now using SIGHUP after lighttpd 1.4.11 has been emerged). However, due to the way lighttpd implemented graceful restart, sometimes I found the FastCGI processes (in this case php-cgi) do not get restarted together with lighttpd. I think it is how it happens.

  1. Run “/etc/init.d/lighttpd restart“, which sends a SIGINT to the old process, and then fire up a new lighttpd process.
  2. Old lighttpd process received SIGINT, unbind the HTTP port to stop accepting new connections, however it cannot be terminated straight away because some of its PHP sub-processes are still finishing up their requests.
  3. New lighttpd process started, and bind itself to HTTP/HTTPS port which are now available. However, it cannot spawn the php-cgi FastCGI process, because port 1026 is still occupied by the php-cgi processes from the old lighttpd instance.
  4. New, old lighttpd process died after all its php-cgi children have finished their tasks. However the new lighttpd process is still left child-less. All new PHP requests will return 500 Internal Error.

I had that happening this morning, and this VM stopped serving PHP scripts for almost 4 hours, until I restarted lighttpd again! It has actually happened quite a few times before, but being procrastinating in nature, I only managed to “do something about it” today.

The solution, for me at least, is to use the spawn-fcgi script that also gets installed when you emerged lighttpd. It starts php-cgi independently from lighttpd, so that restarting lighttpd process do not have to restart all PHP FastCGI processes.

The configuration file can be found in /etc/conf.d/spawn-fcgi, and its default setting is quite reasonable for PHP. It starts 5 PHP FastCGI instance when it starts, and binds to TCP port 1026. First of all, you need to modify your lighttpd’s mod_fastcgi.conf file so that it would not try to look for local executable. All you need to do is to comment out the line where bin-path is specified. For example,

fastcgi.server = (
    ".php" => (
        "localhost" => (
#           "bin-path"  => "/usr/bin/php-cgi",
            "host" => "127.0.0.1",
            "port" => 1026
        )
    )
)

And then you need to restart lighttpd. spawn-fcgi comes with its own init script, so you’ll also need to do

localhost ~ # /etc/init.d/spawn-fcgi start
 * Starting spawn-fcgi ...        [ ok ]
localhost ~ # rc-update add spawn-fcgi default
 * spawn-fcgi added to runlevel default
 * rc-update complete.
localhost ~ #

Yup — remember to use rc-update to add spawn-fcgi to your start up script.

Now starting/stopping lighttpd would not affect starting and stopping of PHP FastCGI processes.