debian squeeze配置nginx支持CGI程序

nginx默认不支持传统的CGI程序,但是通过FCGI包装程序可以让nginx支持CGI

只要是符合FCGI接口的包装程序都可以用来使nginx支持CGI程序,有很多这样的程序,有perl写的,有C写的,也有C++写,等等。

nginx.org提供了一个perl包装程序,但没有提供system V风格的init文件,对这个程序稍加改造,然后写一个init控制文件就可以在debian squeeze上使用了。

安装perl必要的支持库
$sudo apt-get -y install libfcgi-perl libfcgi-procmanager-perl libio-all-perl

改造后的perl包装程序cgiwrap-fcgi.pl代码:
1 #!/usr/bin/perl
2 use FCGI;
3 use Socket;
4 use FCGI::ProcManager;
5 use IO::All;
6 sub shutdown { FCGI::CloseSocket($socket); exit; }
7 sub restart { FCGI::CloseSocket($socket); &main; }
8 use sigtrap ‘handler’, \&shutdown, ‘normal-signals’;
9 use sigtrap ‘handler’, \&restart,  ‘HUP’;
10 require ‘syscall.ph’;
11 use POSIX qw(setsid);
12  
13 &daemonize;
14
15 END()   { }
16 BEGIN() { }
17 {
18   no warnings;
19   CORE::GLOBAL::exit = sub { die “fakeexit\nrc=” . shift() . “\n”; };
20 };
21  
22 eval q{exit};
23 if ($@) {
24   exit unless $@ =~ /**^fakeexit/;
25 }
26 &main;
27  
28 **sub
daemonize() {
29   chdir ‘/‘ or die “Can’t chdir to /: $!”;
30   defined( my $pid = fork ) or die “Can’t fork: $!”;
31   exit if $pid;
32   setsid() or die “Can’t start a new session: $!”;
33   umask 0;
34 }
35  
36 sub main {
37   $$ > io(“/var/run/cgiwrap-fcgi/cgiwrap-fcgi.pid”);
38   $proc_manager = FCGI::ProcManager->new( {n_processes => 2} );
39   $socket = FCGI::OpenSocket( “/var/run/cgiwrap-fcgi/cgiwrap-fcgi.sock”, 10 )
40   ; #use UNIX sockets - user running this script must have w access to the ‘nginx’ folder!!
41   $request =
42   FCGI::Request( \
STDIN, \STDOUT, \STDERR, \%req_params, $socket,
43   &FCGI::FAIL_ACCEPT_ON_INTR );
44   $proc_manager->pm_manage();
45   if ($request) { request_loop() }
46   FCGI::CloseSocket($socket);
47 }
48  
49 sub request_loop {
50   while ( $request->Accept() >= 0 ) {
51     $proc_manager->pm_pre_dispatch();
52  
53     #processing any STDIN input from WebServer (for CGI-POST actions)
54     $stdin_passthrough = ‘’;
55     { no warnings; $req_len = 0 + $req_params{‘CONTENT_LENGTH’}; };
56     if ( ( $req_params{‘REQUEST_METHOD’} eq ‘POST’ ) && ( $req_len != 0 ) ) {
57       my $bytes_read = 0;
58       while ( $bytes_read < $req_len ) {
59         **my** $data = ‘’;
60         **my** $bytes = **read**( STDIN, $data, ( $req_len - $bytes_read ) );
61         **last** **if** ( $bytes == 0  !**defined**($bytes) );
62         $stdin_passthrough .= $data;
63         $bytes_read += $bytes;
64       }
65     }
66  
67     #running the cgi app
68     **if** (
69       ( **-x** $req_params{SCRIPT_FILENAME} ) &&    #can I execute this?
70       ( **-s** $req_params{SCRIPT_FILENAME} ) &&    #Is this file empty?
71       ( **-r** $req_params{SCRIPT_FILENAME} )       #can I read this file?
72     ) {
73       **pipe**( CHILD_RD,   PARENT_WR );
74       **pipe**( PARENT_ERR, CHILD_ERR );
75       **my** $pid = **open**( CHILD_O, “-“ );
76       **unless** ( **defined**($pid) ) {
77         **print**(“Content-type: text/plain\r\n\r\n”);
78         **print** “Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n”;
79         **next**;
80       }
81       $oldfh = **select**(PARENT_ERR);
82       $     = 1;
83       **select**(CHILD_O);
84       $ = 1;
85       **select**($oldfh);
86       **if** ( $pid > 0 ) {
87         close(CHILD_RD);
88         close(CHILD_ERR);
89         print PARENT_WR $stdin_passthrough;
90         close(PARENT_WR);
91         $rin = $rout = $ein = $eout = ‘’;
92         vec( $rin, fileno(CHILD_O),    1 ) = 1;
93         vec( $rin, fileno(PARENT_ERR), 1 ) = 1;
94         $ein    = $rin;
95         $nfound = 0;
96  
97         while ( $nfound = select( $rout = $rin, undef, $ein = $eout, 10 ) ) {
98           die “$!” unless $nfound != -1;
99           $r1 = vec( $rout, fileno(PARENT_ERR), 1 ) == 1;
100           $r2 = vec( $rout, fileno(CHILD_O),    1 ) == 1;
101           $e1 = vec( $eout, fileno(PARENT_ERR), 1 ) == 1;
102           $e2 = vec( $eout, fileno(CHILD_O),    1 ) == 1;
103  
104           if ($r1) {
105             while ( $bytes = read( PARENT_ERR, $errbytes, 4096 ) ) {
106               print STDERR $errbytes;
107             }
108             if ($!) {
109               $err = $!;
110               die $!;
111               vec( $rin, fileno(PARENT_ERR), 1 ) = 0
112               unless ( $err == EINTR or $err == EAGAIN );
113             }
114           }
115           if ($r2) {
116             while ( $bytes = read( CHILD_O, $s, 4096 ) ) {
117               print $s;
118             }
119             if ( !defined($bytes) ) {
120               $err = $!;
121               die $!;
122               vec( $rin, fileno(CHILD_O), 1 ) = 0
123               unless ( $err == EINTR or $err == EAGAIN );
124             }
125           }
126           last if ( $e1  $e2 );
127         }
128         close CHILD_RD;
129         close PARENT_ERR;
130         waitpid( $pid, 0 );
131       } else {
132         foreach $key ( keys %req_params ) {
133           $ENV{$key} = $req_params{$key};
134         }
135  
136         # cd to the script’s local directory
137         if ( $req_params{SCRIPT_FILENAME} =~ */**^(.)\/[^\/] +$/ ) {
138           chdir $1;
139         }
140         close(PARENT_WR);
141         #close(PARENT_ERR);
142         close(STDIN);
143         close(STDERR);
144  
145         #fcntl(CHILD_RD, F_DUPFD, 0);
146         syscall( &SYS_dup2, fileno(CHILD_RD),  0 );
147         syscall( &SYS_dup2, fileno(CHILD_ERR), 2 );
148  
149         #open(STDIN, “<&CHILD_RD”);
150         exec( $req_params{SCRIPT_FILENAME} );
151         die(“exec failed”);
152       }
153     } else {
154       print(“Content-type: text/plain\r\n\r\n”);
155       print “Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n”;
156     }
157   }
158 }

system V风格的init文件cgiwrap-fcgi:
1 #!/bin/sh
2
3 ### BEGIN INIT INFO
4 # Provides:         cgiwrap-fcgi
5 # Required-Start:   $local_fs
6 # Required-Stop:    $local_fs
7 # Should-Start:     $syslog
8 # Should-Stop:      $syslog
9 # Default-Start:    2 3 4 5
10 # Default-Stop:     0 1 6
11 # Short-Description:fcgi support for nginx
12 # Description:      cgiwrap-fcgi is a perl script to provide simple cgi support for nginx http daemon
13 ### END INIT INFO
14
15 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
16 DAEMON=/usr/local/bin/cgiwrap-fcgi.pl
17 NAME=cgiwrap-fcgi
18 DESC=“**cgiwrap-fcgi daemon“**
19 CGIWRAP_FCGIPIDDIR=/var/run/cgiwrap-fcgi
20 CGIWRAP_FCGIPID=$CGIWRAP_FCGIPIDDIR/cgiwrap-fcgi.pid
21
22 check_nginx_fcgi_piddir(){
23     if test ! -d $CGIWRAP_FCGIPIDDIR*;** then
24         mkdir -m 02700 $CGIWRAP_FCGIPIDDIR**”**
25         chown www-data:www-data $CGIWRAP_FCGIPIDDIR**”**
26     fi
27
28     if test ! -x $CGIWRAP_FCGIPIDDIR**;** then
29         echo “**Cannot access $CGIWRAP_FCGIPIDDIR directory,are you root?“** >**&2
30         **exit
 1
31     fi
32 }
33
34 start() {
35     check_nginx_fcgi_piddir
36     echo “**Starting $DESC: $NAME…“**
37
38     start-stop-daemon --start --quiet --oknodo --pidfile $CGIWRAP_FCGIPID \
39     --chuid www-data:www-data  --exec $DAEMON > /dev/null 2>&1
40     echo “**done.“**
41 }
42
43 stop() {
44     echo -n “**Stopping $DESC: **”
45     pid=`cat $CGIWRAP_FCGIPID 2>/dev/null`  true
46
47     if test ! -f $CGIWRAP_FCGIPID -o -z $pid**”;** then
48         echo “**not running ( there is no $CGIWRAP_FCGIPID).“**
49         exit 0
50     fi
51
52     if kill $pid ; then
53         cat /dev/null > $CGIWRAP_FCGIPID**;**
54         echo “**success!“**
55     else
56         echo “**Can’t stop $DESC“**
57     fi
58
59     return 0
60 }
61
62 status() {
63     pid=`cat $CGIWRAP_FCGIPID 2>/dev/null`  true
64
65     if [ -z ${pid} ]**;** then
66         echo ${DESC} is not running.
67     else
68         echo ${DESC} is running.
69     fi
70 }
71
72 RETVAL=0
73
74 case $1**”** in
75     start**)**
76         start
77         ;;
78     stop**)**
79         stop
80         ;;
81     restart**)**
82         stop
83         start
84         ;;
85     force-reload**)**
86         ;;
87     status**)**
88        status
89         ;;
90     **
)**
91         echo $0 {startstoprestartforece-reloadstatus}
92         exit 3
93         ;;
94 esac
95
96 exit $RETVAL

这个init控制文件支持start,stop,status,restart,forec-reload控制指令。

下载以后,将cgiwrap-fcgi.pl拷贝到/usr/local/bin/目录下,将cgiwrap-fcgi拷贝到/etc/init.d/目录下,然后执行:
$sudo update-rc.d cgiwrap-fcgi defaults
更新/etc/rcX.d目录下的符号链接,这样debian启动时会自动启动cgiwrap-fcgi.pl程序

手动控制cgiwarp-fcgi.pl程序

$sudo /etc/init.d/cgiwrap-fcgi restart #重新启动
$sudo /etc/init.d/cgiwrap-fcgi stop #停止
$sudo /etc/init.d/cgiwrap-fcgi status #查看cgiwrap-fcgi的运行状态

cgiwrap-fcgi.pl使用unix socket文件/var/run/cgiwrap-fcgi/cgiwrap-fcgi.sock来监听CGI程序请求,因此只要将对nginx的CGI请求转发到此socket即可,对应的nginx配置文件cgiwrap-fcgi.conf为:
1 location ~ \.(cgipl).*$ {
2     gzip off;
3     fastcgi_pass unix:/var/run/cgiwrap-fcgi/cgiwrap-fcgi.sock;
4     fastcgi_index index.cgi;
5     include fastcgi_params;
6 }
下载后将此文件拷贝到/etc/nginx/目录下,然后在虚拟主机配置文件的server节include cgiwrap-fcgi.conf即可。

三个文件的打包下载