Never been to TextSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

« Newer Snippets
Older Snippets »
14 total  XML / RSS feed 

nginx on FreeBSD with PHP, fastcgi, Drupal, MySQL

// A method for installing LightTPD, PHP, MySQL on FreeBSD
// All source is stored in /usr/local/src
// Source tarballs are in /usr/local/src/tarballs

// nginx web server install on FreeBSD 6.2
// Links:
// http://wiki.codemongers.com/Nginx
// http://blog.kovyrin.net/category/web-tech/nginx/
// http://blog.kovyrin.net/2006/05/30/nginx-php-fastcgi-howto/
// http://blog.kovyrin.net/files/nginx-conf/php-fcgi.nginx.conf
// http://sysoev.ru/nginx/download.html

su
cd /usr/local/src/tarballs
fetch http://sysoev.ru/nginx/nginx-0.5.20.tar.gz
cd ..
tar zxvf tarballs/nginx-0.5.20.tar.gz
cd tarballs/nginx-0.5.20
less README 
  The English documentation is available at http://nginx.net

# Some configuration options:
PREFIX: Let -prefix= default to /usr/local/nginx
--with-cc-opt="-I /usr/local/include"

# from http://wiki.codemongers.com/NginxInstall:
# --with-cc-opt=OPTIONS - Additional parameters which will be added to the variable CFLAGS.
# With the use of the system library PCRE in FreeBSD, it is necessary to indicate 
# --with-cc-opt="-I /usr/local/include". If we are using select() and it is necessary
# to increase the number of file descriptors, then this also can be assigned here:
# --with-cc-opt="-D FD_SETSIZE=2048".

# Look for configuration options:
./configure --help

# Make directory for log files (my preferences!)
mkdir /var/log/nginx
mkdir /var/log/nginx/drupal
chmod -R 777 /var/log/nginx

mkdir /usr/local/etc/nginx
chown www /usr/local/etc/nginx
chmod 775 /usr/local/etc/nginx

# I tell it where to put the nginx binary. Specifically not in the path. Scripts will start it.
# I like to put conf files in /usr/local/etc/
# I like to put pid files in /var/run
# I have PCRE in /usr/local/include (look for pcre.h)
./configure \
  --sbin-path=/usr/local/nginx/nginx \
  --conf-path=/usr/local/etc/nginx/nginx.conf \
  --pid-path=/var/run/nginx.pid 
  --with-cc-opt="-I /usr/local/include/pcre"

Configuration summary
  + threads are not used
  + using system PCRE library
  + OpenSSL library is not used
  + md5 library is not used
  + sha1 library is not used
  + using system zlib library

  nginx path prefix: "/usr/local/nginx"
  nginx binary file: "/usr/local/nginx/nginx"
  nginx configuration file: "/usr/local/etc/nginx/nginx.conf"
  nginx pid file: "/var/run/nginx.pid"
  nginx error log file: "/usr/local/nginx/logs/error.log"
  nginx http access log file: "/usr/local/nginx/logs/access.log"
  nginx http client request body temporary files: "/usr/local/nginx/client_body_temp"
  nginx http proxy temporary files: "/usr/local/nginx/proxy_temp"
  nginx http fastcgi temporary files: "/usr/local/nginx/fastcgi_temp"

make
make install

cd /usr/local/nginx
total 1492
drwxr-xr-x  2 root  wheel      512 May 16 15:56 html
drwxr-xr-x  2 root  wheel      512 May 16 15:56 logs
-rwxr-xr-x  1 root  wheel  1495320 May 16 15:56 nginx
v4# ls -l /usr/local/etc/nginx
total 28
-rw-r--r--  1 root  wheel  2837 May 16 15:56 koi-utf
-rw-r--r--  1 root  wheel  2223 May 16 15:56 koi-win
-rw-r--r--  1 root  wheel  2944 May 16 15:56 mime.types
-rw-r--r--  1 root  wheel  2944 May 16 15:56 mime.types.default
-rw-r--r--  1 root  wheel  2702 May 16 15:40 nginx.conf
-rw-r--r--  1 root  wheel  2702 May 16 15:56 nginx.conf.default
-rw-r--r--  1 root  wheel  3610 May 16 15:56 win-utf

# Here's my nginx.conf file
# Note that I serve Drupal (drupal.org) with it.
# I use PHP5 and fastcgi (with spawn-fcgi from the lighttpd installation)
##############################################
user  www;
worker_processes  1;

error_log   /var/log/nginx/error.log debug;

pid         /var/log/nginx/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /usr/local/etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    
    server {
        # Test operations on port 81.
        #listen          81;
        # Normal operations on port 80.
        listen               80;
        server_name     domain.com alias1.domain.com alias2.domain.com;
        access_log      /var/log/nginx/drupal/access.log;

        location / {
            index index.php;
            root  /var/www/drupal;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        location ~ \.php$ {
            include /usr/local/etc/nginx/fastcgi.conf;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
        }
    }

}
##################################################

# Here's my fastcgi.conf file:
##################################################
#fastcgi.conf
fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx;

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_FILENAME    /var/www/drupal$fastcgi_script_name;
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  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;
##################################################

# Test nginx configuration
/usr/local/nginx/nginx -t -c /usr/local/etc/nginx/nginx.conf
2007/05/16 16:10:37 [info] 6369#0: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
2007/05/16 16:10:37 [info] 6369#0: the configuration file /usr/local/etc/nginx/nginx.conf was tested successfully

# Run it on port 81. Note that conf file was modified. Change it back for production use.
# First spawn an FCGI process to pass PHP scripts to.
# php was compiled like this:
# ./configure --enable-cgi --enable-fastcgi --enable-force-redirect (plus more flags)
# so PHP resides in /usr/local/bin/
# Note I specified port 9000 in the nginx.conf file. Must match here:
/usr/local/bin/spawn-fcgi -f /usr/local/bin/php -a 127.0.0.1 -p 9000 -u www

// output: spawn-fcgi.c.190: child spawned successfully: PID: 6414

# Then start the nginx.
/usr/local/nginx/nginx -c /usr/local/etc/nginx/nginx.conf

ps ax | grep nginx

// output:
// 6425  ??  Ss     0:00.00 nginx: master process /usr/local/nginx/nginx -c /usr/local/etc/nginx/nginx.conf (nginx)
// 6426  ??  S      0:00.00 nginx: worker process (nginx)

# Now we have to try it on port 80 to see if Drupal works
# Graceful shutdown of server
kill -15 6425

# Edit .conf file, restart:
/usr/local/nginx/nginx -c /usr/local/etc/nginx/nginx.conf

ps ax | grep nginx

// output:
// 6447  ??  Ss     0:00.00 nginx: master process /usr/local/nginx/nginx -c /usr/local/etc/nginx/nginx.conf (nginx)
// 6448  ??  S      0:00.00 nginx: worker process (nginx)

# restart the server gracefully if necessary. Just need pid.
kill -HUP 6447

PHP on mod_fcgid with Apache2 and mod_suexec

This took a little doing and some major tweaking. Assuming you have the LoadModule line already...

  AddHandler fcgid-script .php

  <Directory /home/elitesys/elite-systems.org/html>
    FCGIWrapper /home/elitesys/elite-systems.org/html/php.fcgi .php
  Directory>

  IPCConnectTimeout 20
  IPCCommTimeout 300


Add the handler for php files, specify the wrapper (in this case the file in the root of the site) and setup connect and communication timeouts. The timeouts are in seconds and you need to set it like that or higher or else file uploads will timeout and I have heard of issues with Wordpress if you don't increase it.

And in php.fcgi...
#!/bin/sh
PHPRC="/usr/php4/etc"
export PHPRC
PHP_FCGI_CHILDREN=4
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/php4/bin/php


This should look familiar to another post...

There isn't a definition for suexec in terms of executable location. There doesn't have to be. Apache will automatically wrap it properly. This configuration is far easier than mod_fastcgi and works just as well. Probably easily expanded to work with ruby on rails although I havn't tried yet...

PHP as FastCGI program

If you have problem with compiling php as cgi-fastcgi *run* make clean. It worked for me and, probably, it will work for you.

And here's my ./configure options for compiling php as cgi-fastcgi with some features I need.

simanyay $ make clean
simanyay $ ./configure --prefix=/usr/local/php5/ --enable-mbstring --with-mysql=/usr/local/mysql --with-mysql-sock=/t
mp/mysql.sock --with-mysqli --with-pdo-mysql=/usr/local/mysql --enable-force-cgi-redirect --enable-fastcgi --with-cur
l --with-sockets --enable-memory-limit --with-config-file-scan-dir=/usr/local/php5/sharecfg
simanyay $ make
simanyay $ sudo make install
simanyay $ /usr/local/php5/bin/php -v
PHP 5.1.4 (cgi-fcgi) (built: May 23 2006 20:03:51)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies

Getting HTTP Auth to play nice with PHP run under FastCGI

<?php
/**
 * Get HTTP Auth to work with PHP+FastCGI
 *
 * @author  Jacques Marneweck 
 * @license PHP License v3.01
 */

/**
 * Get HTTP Auth to work with PHP+FastCGI
 */

    

if (isset($_SERVER["AUTHORIZATION"]) && !empty($_SERVER["AUTHORIZATION"])) {

    list ($type, $cred) = split (" ", $_SERVER['AUTHORIZATION']);

    if ($type == 'Basic') {
        list ($user, $pass) = explode (":", base64_decode($cred));
        $_SERVER['PHP_AUTH_USER'] = $user;
        $_SERVER['PHP_AUTH_PW'] = $pass;
    }

}

How TextDrive does both PHP and Rails FCGI in one thing-a-ma-bob

fastcgi.server = (
".fcgi" =>
                    ( "localhost" =>
                        (
                            "socket" => "/tmp/textdrive-new.socket",
                            "bin-path" => "/users/home/website/web/public/dispatch.fcgi",
                            "bin-environment" => ( "RAILS_ENV" => "production" )
                        )
                    ),
".php" =>
                    ( "localhost" =>
                        (
                            "socket" => "/tmp/textdrive-php5-fcgi.socket",
                            "bin-path" => "/usr/local/www/cgi-bin/php5-fcgi",
                            "bin-environment" => (
                            "PHP_FCGI_CHILDREN" => "4",   
                            "PHP_FCGI_MAX_REQUESTS" => "5000"
                                                 )
                        )       
                    )
)

yet another lighttpd restart script

#!/bin/sh

USERNAME=username
LIGHTTPD_CONF=/home/$USERNAME/service/lighttpd.conf
PIDFILE=/home/$USERNAME/service/logs/lighttpd.pid
HTTPD=/home/$USERNAME/lighttpd/sbin/lighttpd

PID=0
if [ -e $PIDFILE ]; then
    PID=`cat $PIDFILE`
    if [ "x" == "x$PID" ]; then
        PID=0
    fi
fi

case "$1" in
    start)
        if [ 0 -ne $PID ]; then
            running=`ps --pid $PID | grep $PID`
            if [ $running ]; then
                echo "lighttpd is already running"
                exit 1
            fi
            rm $PIDFILE
            PID=0
        fi
        $HTTPD -f $LIGHTTPD_CONF
        ;;
    stop)
        if [ 0 -eq $PID ]; then
            echo "lighttpd was not running"
            exit 1
        fi
        kill $PID
        tries=""
        while [ -e $PIDFILE ]; do
            if [ "x$tries" == "x.........." ]; then
                break
            fi
            sleep 2
            tries=".$tries"
        done
        if [ -e $PIDFILE ]; then
            echo "lighttpd did not go gentle into that good night, murdering"
            kill -9 $PID
            rm $PIDFILE
        fi
        ;;
    restart)
        $0 stop
        $0 start
        ;;
    reload)
        if [ 0 -eq $PID ]; then
            echo "lighttpd was not running"
        fi
        kill -HUP $PID
        ;;
    *)
        echo "Usage: "`basename $0`" (start|stop|restart|reload)"
        exit 1
        ;;
esac

Daedalus Config to Keep Lighttpd Up Nicely

This daedalus config as well as my previous snippet is meant to supplement chapter 5 of "Lighttpd the painless way".

This config is dependent on having a ~/lighttpd directory setup as described in that manual. Also, you must have the restart.rb script (again from my previous snippet) in the lighttpd folder.

As before, remember to swap out your USERNAME, DOMAIN, and PORT.

The first check here is that a lighttpd process is running. If not then it calls restart.rb which will kill any zombie dispatchers and restart lighttpd.

The second check is more of a departure from the original suggestion. Rather than checking that a specific file is generating the expected output, I go right to the source and verify that lighttpd is responding with an HTTP header on the port you were assigned. This is a pure indication of whether lighttpd is responsive on the correct port. It won't be fouled up by application errors or apache forwarding misconfiguration. More importantly, it won't generate a flood of restarts due to an unrelated code error.

Also, you will notice I set the checkinterval to 10 minutes. I felt this was a good compromise between keeping lighttpd up and saturating the server with unnecessary processing.

name: lighttpd
checkcommand: /bin/ps axww
checkregex: /lighttpd/
onfailcommand: /home/USERNAME/lighttpd/restart.rb
checkinterval: 600 
aftercommandwait: 120

name: lighttpd-external
checkcommand: /usr/local/bin/curl -I http://YOURDOMAIN.com:YOURPORT
checkregex: /^HTTP/s
onfailcommand: /usr/bin/killall -9 lighttpd; /home/USERNAME/lighttpd/restart.rb
checkinterval: 600 
aftercommandwait: 120

Killing rogue dispatch.fcgi processes and starting lighttpd on TextDrive

By using this script to start lighttpd you can be sure you won't be leaving rogues dispatchers around sucking up memory and generally pissing jason off. Don't get caught with your pants down!

Make sure to change USERNAME below, as well as any paths that may be different in your case.

#!/usr/local/bin/ruby
#Modified from Julik's original code posted to TextDrive forums.

pstab = `ps axww`

def kill_fcgi_proc(line)
  its = line.strip.split(/\s+/)
  pid = its[0]
  puts "KILLING #{line}"
  `kill -9 #{pid}`
  sleep(3)
end

if pstab =~ /\/usr\/local\/sbin\/lighttpd -f/
  
  puts "Lighttpd still running."

else

  pstab.scan(/^.*dispatch\.fcgi\s*$/) do |line|
    kill_fcgi_proc line
  end

  pstab = `ps axww`
  
  if pstab =~ /dispatch\.fcgi/
    puts "Error, rogue dispatch.fcgi's still pissing jason off."
  else
    puts "Rogue dispatch.fcgi's cleared, starting lighty!"
    `/usr/local/sbin/lighttpd -f /home/USERNAME/lighttpd/lighttpd.conf`
  end
  
end

How to configure MySQL for UTF8 when running MovableType as FastCGI


Use the modified dispatcher.

#!/usr/bin/perl -w

use strict;
use MT::Bootstrap;
use CGI::Fast;

# preload app packages
use MT::App::CMS;
use MT::App::Comments;
use MT::App::Trackback;
use MT::App::Search;
## uncomment if necessary, but this adds a lot of
## overhead since it loads up LibXML.
##use MT::AtomServer;


my $handlers = {
    'mt.fcgi' => { class => 'MT::App::CMS', name => 'AdminScript' },
    'mt-comments.fcgi' => { class => 'MT::App::Comments', name => 'CommentScript' },
    'mt-tb.fcgi' => { class => 'MT::App::Trackback', name => 'TrackbackScript' },
    'mt-search.fcgi' => { class => 'MT::App::Search', name => 'SearchScript' },
## See note above about this...
##    'mt-atom.fcgi' => { class => 'MT::AtomServer', name => 'AtomScript' },
};

eval {
    while (my $q = new CGI::Fast) {
        my $cgi = $q->script_name;
        $cgi =~ s!.*/!!;
        my $pkg = $handlers->{$cgi}{class};
        die "Invalid handler for $cgi" unless $pkg;
        my $app = $pkg->new(CGIObject => $q) or die $pkg->errstr;
        local $SIG{__WARN__} = sub { $app->trace($_[0]) };
        $app->init_request(CGIObject => $q) unless $app->{init_request};
        fixup_script_names($app);
        
        # do a little nasty over-the-back jump and setup MySQL on every connection        
        my $driver = MT::Object->driver;
        my $dbh = $driver->{dbh};
              my $names_cmd = $dbh->prepare("SET NAMES UTF8");
        $names_cmd->execute();
    
        $app->run;
        my $mode = $app->mode || '';
        if ("$pkg->$mode" eq 'MT::App::CMS->plugin_control') {
            exit; # allows server to recycle after changing plugin switches
        }
    }
};
if ($@) {
    print "Content-Type: text/htmlnn";
    print "Got an error: $@";
}

sub fixup_script_names {
    my ($app) = @_;
    $app->config($handlers->{$_}{name}, $_) foreach keys %$handlers;
}

Compile PHP5 with Fast-cgi support for lighttpd

The following is my setup on OS X 10.4.2 using PHP 5.0.5

./configure --prefix=/usr/local/php5-fcgi --enable-fastcgi --enable-force-cgi-redirect --disable-cli --enable-memory-limit --with-layout=GNU --with-regex=php

make

sudo make install


The compile flags enable a fairly basic PHP setup, you may need to add more options for things like MySQL, etc. DO NOT ADD --with-apxs OR --with-apxs2 AS A COMPILE FLAG -- THESE ARE APACHE ONLY AND WILL PROBABLY BREAK UNDER LIGHTTPD!

Add the following to your lighttpd.conf file

fastcgi.server = ( ".php" =>
                   ( "localhost" =>
                     ( "socket" => "/tmp/php5-fcgi.socket",
                       "bin-path" => "/usr/local/php5-fcgi/bin/php"
                     )
                   )
                 )


Restart lighttpd, now with PHP support

Use curl and a list of URLs to check for Internal Server Errors on Rails Apache Installs

This isn't a benchmark, but it's a great way to send a lot of requests to your box and check if there's anything wrong with your FastCGI setup:


for url in `cat urlslist.txt`;
do
    COUNTER=0
    while [  $COUNTER -lt 2 ]; do
        echo -n ${COUNTER}-
        curl --silent --user yourUSER:yourPASS $url | grep "Internal"
        let COUNTER=COUNTER+1 
    done
done

Minimal extension-less build of PHP-CGI-FCGI

But what you do is add the --with-config-file-scan-dir where you add an extra extensions.ini file that dynamically loads different php extensions that you compile separately.

You will need to have compiled and installed libxml into /usr/local/ or if you are on Mac's Tiger, you can change the path to /usr and that should do ya.

./configure --enable-memory-limit --with-layout=GNU --with-config-file-scan-dir=/usr/local/etc/php --disable-all --enable-libxml --with-libxml-dir=/usr/local --enable-spl --with-regex=php --disable-cli --enable-force-cgi-redirect --enable-fastcgi


And you don't want to leave that /usr/local/bin/php binary sitting there because it's cgi-fcgi, you're going to replace it with php-cli

mv /usr/local/bin/php /usr/local/bin/php-fcgi


/usr/local/bin/php-fcgi is then the binary you use for all PHP CGI and FCGI.

My lighttpd php-fastcgi config with it's own php.ini

fastcgi.server = (
                ".php" =>
                    ( "localhost" =>
                        (
                            "socket" => "/home/jah/tmp/jah-php5-fcgi.socket",
                            "bin-path" => "/usr/local/www/cgi-bin/php5-fcgi -c /home/jah/etc/php.ini",
                            "bin-environment" => (
                            "PHP_FCGI_CHILDREN" => "4",
                            "PHP_FCGI_MAX_REQUESTS" => "5000"
                                                 )
                        )
                    )
                 )

Suexec'ed PHP-FastCGI on Apache2

A PHP cgi binary compiled with fcgi support

> /usr/local/www/cgi-bin/php5-fcgi -v
PHP 5.0.3 (cgi-fcgi) (built: Dec 30 2004 22:44:32)


Central config in httpd.conf

<IfModule mod_fastcgi.c>
FastCgiIpcDir /usr/local/www/fcgi_ipc/tmp
AddHandler fastcgi-script .fcgi
FastCgiSuexec /usr/local/sbin/suexec
FastCgiConfig -singleThreshold 100 -killInterval 300 -autoUpdate -idle-timeout 240 -pass-header HTTP_AUTHORIZATION
IfModule>
/php-fastcgi/>
Options ExecCGI        
SetHandler fastcgi-script
Location>


In a virtual host

SuexecUserGroup ${USER} ${GROUP}
ScriptAlias /php-fastcgi/ ${HOME}/php-fastcgi/ 
AddType application/x-httpd-fastphp .php
Action application/x-httpd-fastphp /php-fastcgi/php5-fcgi


And then the ${HOME}/php-fastcgi/php5-fcgi wrapper

#!/bin/sh 
PHPRC="/usr/local/etc" 
export PHPRC 
PHP_FCGI_CHILDREN=8 
export PHP_FCGI_CHILDREN 
PHP_FCGI_MAX_REQUESTS=5000 
export PHP_FCGI_MAX_REQUESTS 
exec /usr/local/www/cgi-bin/php5-fcgi 


The PHPRC environment sets the directory where php.ini is to be found
« Newer Snippets
Older Snippets »
14 total  XML / RSS feed