nginx支持cgi

扫码查看
nginx支持cgi 想在现有环境LNMP上部署一下Nagios,但是发现默认情况下Nginx自身是无法解析外部CGI程序的,于是官方给出了一个这样的做法http://wiki.nginx.org/NginxSimpleCGI,通过研究发现有两种方式可以实现让nginx支持cgi,两种方式都需要安装那几包.下面分别来介绍: 第一种方式操作步骤:一、安装perl库perl-FCGI、perl-FCGI-ProcManager、perl-IO-ALL(如下文件均可以去http://search.cpan.org下载)#wgethttp://www.cpan.org/modules/by-module/FCGI/FCGI-0.67.tar.gz#tar zxvf FCGI-0.67.tar.gz#cd FCGI-0.67#perl Makefile.PL#make && make install #wget http://search.cpan.org/CPAN/authors/id/B/BO/BOBTFISH/FCGI-ProcManager-0.24.tar.gz#tar zxvf FCGI-ProcManager-0.24.tar.gz#cd FCGI-ProcManager-0.24#perl Makefile.PL#make && make install #wgethttp://search.cpan.org/CPAN/authors/id/I/IN/INGY/IO-All-0.39.tar.gz#tar zxvf IO-All-0.39.tar.gz#cd IO-All-0.39#perl Makefile.PL#make && make install  二、生成perl守护进程#vi nginx-cgi.pl,然后加入如下内容 #!/usr/bin/perl use FCGI; use Socket; use FCGI::ProcManager; sub shutdown { FCGI::CloseSocket($socket); exit; } sub restart  { FCGI::CloseSocket($socket); &main; } use sigtrap 'handler', \&shutdown, 'normal-signals'; use sigtrap 'handler', \&restart,  'HUP'; require 'syscall.ph'; use POSIX qw(setsid);   END()   { } BEGIN() { } {   no warnings;   *CORE::GLOBAL::exit = sub { die "fakeexit\nrc=" . shift() . "\n"; }; };   eval q{exit}; if ($@) {   exit unless $@ =~ /^fakeexit/; } &main;   sub daemonize() { chdir '/' or die "Can't chdir to /: $!"; defined( my $pid = fork ) or die "Can't fork: $!";   exit if $pid; setsid() or die "Can't start a new session: $!"; umask 0; }   sub main {   $proc_manager = FCGI::ProcManager->new( {n_processes => 5} );   $socket = FCGI::OpenSocket( "127.0.0.1:8999", 10 )   ; #use UNIX sockets - user running this script must have w access to the 'nginx' folder!!   $request =   FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket, &FCGI::FAIL_ACCEPT_ON_INTR );   $proc_manager->pm_manage();   if ($request) { request_loop() }   FCGI::CloseSocket($socket); }   sub request_loop {   while ( $request->Accept() >= 0 ) {     $proc_manager->pm_pre_dispatch();       #processing any STDIN input from WebServer (for CGI-POST actions)     $stdin_passthrough = '';     { no warnings; $req_len = 0 + $req_params{'CONTENT_LENGTH'}; };     if ( ( $req_params{'REQUEST_METHOD'} eq 'POST' ) && ( $req_len != 0 ) ) {       my $bytes_read = 0;       while ( $bytes_read         my $data = '';         my $bytes = read( STDIN, $data, ( $req_len - $bytes_read ) );         last if ( $bytes == 0 || !defined($bytes) );         $stdin_passthrough .= $data;         $bytes_read += $bytes;       }     }       #running the cgi app     if (       ( -x $req_params{SCRIPT_FILENAME} ) &&    #can I execute this?       ( -s $req_params{SCRIPT_FILENAME} ) &&    #Is this file empty?       ( -r $req_params{SCRIPT_FILENAME} )       #can I read this file?     ) {       pipe( CHILD_RD,   PARENT_WR );       pipe( PARENT_ERR, CHILD_ERR );       my $pid = open( CHILD_O, "-|" );       unless ( defined($pid) ) {         print("Content-type: text/plain\r\n\r\n");         print "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n";         next;       }       $oldfh = select(PARENT_ERR);       $|     = 1;       select(CHILD_O);       $| = 1;       select($oldfh);       if ( $pid> 0 ) {         close(CHILD_RD);         close(CHILD_ERR);         print PARENT_WR $stdin_passthrough;         close(PARENT_WR);         $rin = $rout = $ein = $eout = ''; vec( $rin, fileno(CHILD_O),    1 ) = 1; vec( $rin, fileno(PARENT_ERR), 1 ) = 1;         $ein    = $rin;         $nfound = 0;           while ( $nfound = select( $rout = $rin, undef, $ein = $eout, 10 ) ) {           die "$!" unless $nfound != -1;           $r1 = vec( $rout, fileno(PARENT_ERR), 1 ) == 1;           $r2 = vec( $rout, fileno(CHILD_O),    1 ) == 1;           $e1 = vec( $eout, fileno(PARENT_ERR), 1 ) == 1;           $e2 = vec( $eout, fileno(CHILD_O),    1 ) == 1;             if ($r1) {             while ( $bytes = read( PARENT_ERR, $errbytes, 4096 ) ) {               print STDERR $errbytes;             } if ($!) {               $err = $!; die $!; vec( $rin, fileno(PARENT_ERR), 1 ) = 0               unless ( $err == EINTR or $err == EAGAIN );             }           }           if ($r2) {             while ( $bytes = read( CHILD_O, $s, 4096 ) ) {               print $s;             }             if ( !defined($bytes) ) {               $err = $!; die $!; vec( $rin, fileno(CHILD_O), 1 ) = 0               unless ( $err == EINTR or $err == EAGAIN );             }           }           last if ( $e1 || $e2 );         }         close CHILD_RD;         close PARENT_ERR; waitpid( $pid, 0 );       } else { foreach $key ( keys %req_params ) {           $ENV{$key} = $req_params{$key};         }           # cd to the script's local directory if ( $req_params{SCRIPT_FILENAME} =~ /^(.*)\/[^\/] +$/ ) { chdir $1;         }         close(PARENT_WR);         #close(PARENT_ERR);         close(STDIN);         close(STDERR);           #fcntl(CHILD_RD, F_DUPFD, 0); syscall( &SYS_dup2, fileno(CHILD_RD),  0 ); syscall( &SYS_dup2, fileno(CHILD_ERR), 2 );           #open(STDIN, "         exec( $req_params{SCRIPT_FILENAME} );         die("exec failed");       }     } else {       print("Content-type: text/plain\r\n\r\n");       print "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n";     }   } } #chmod 777 nginx-cgi.pl#/usr/local/nginx/sbin/nginx-cgi.pl>/dev/null &   //启动FCGI#echo "/usr/local/nginx/sbin/nginx-cgi.pl>/dev/null &" >>/etc/rc.local注:FCGI监听地址为127.0.0.1:8999,如想改变可以在nginx-cgi.pl内修改  三、配置NginxNginx配置如下 server {   listen 80;   index index.phpindex.cgi; server_name blog.carl.com;   root           /usr/local/nginx/html;   location ~ \.php$ { fastcgi_pass unix:/usr/local/nginx/php-cgi.sock; fastcgi_indexindex.php; fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;   include        fastcgi_params;   }   location ~ \.cgi$ {   root /usr/local/nginx/html; fastcgi_pass 127.0.0.1:8999; fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;   include fastcgi_params;   }   }  四、测试#vi /usr/local/nginx/html/test.cgi #!/usr/bin/perl print "Content-type: text/html\n\n"; print "Hello, world."; 然后打开浏览器访问http://localhost/test.cgi,如果出现内容为Hello,world.则说明配置成功。   第二种方式:vi /usr/local/nginx/perl-fcgi.pl #!/usr/bin/perl##       author               Daniel Dominik Rudnicki#       thanksto:         Piotr Romanczuk#       email                  daniel@sardzent.org#       version              0.4.3#       webpage           http://www.nginx.eu/##       BASED@ http://wiki.codemongers.com/NginxSimpleCGI### use strict;use FCGI;use Getopt::Long;use IO::All;use Socket; sub init {         GetOptions(     "h"   => \$help,                            "verbose!"=>\$verbose,                            "pid=s"     => \$filepid,                            "l=s"=> \$logfile,                            "S:s"   => \$unixsocket,                            "P:i"   => \$unixport) or usage();                   usage()if $help;          print"       Starting Nginx-fcgi\n"if $verbose;         print"       Running with $> UID"if $verbose;         print"       Perl $]" if $verbose;          if( $> == "0" ) {                   print"\n\tERROR\tRunning as a root!\n";                   print"\tSuggested not to do so !!!\n\n";                   exit1;         }         if ( ! $logfile ) {                   print"\n\tERROR\t log file must declared\n"                            ."\tuse $0 with option -l filename\n\n";                   exit1;         }         print"       Using log file$logfile\n" if $verbose;         "\n\n">> io($logfile);         addlog($logfile,"Starting Nginx-cfgi");         addlog($logfile,"Running with $> UID");         addlog($logfile,"Perl $]");         addlog($logfile,"Testing socket options");          if( ($unixsocket && $unixport) || (!($unixsocket) && !($unixport))) {                   print"\n\tERROR\tOnly one option can be used!\n";                   print"\tSuggested (beacuse of speed) is usage UNIX socket -S \n\n";                   exit1;         }          if($unixsocket) {                   print"       Daemon listening at UNIXsocket $unixsocket\n" if $versbose;                   addlog($logfile,"Deamon listening at UNIX socket $unixsocket");         }else {                   print"       Daemon listening at TCP/IPsocket *:$unixport\n" if $verbose;                   #                   addlog($logfile,"Daemon listening at TCP/IP socket *:$unixport");         }          if( -e $filepid ) {                   print"\n\tERROR\t PID file $filepid already exists\n\n";                   addlog($logfile,"Can not use PID file $filepid, already exists.");                   exit1;         }          if( $unixsocket ) {                   print"       Creating UNIX socket\n"if $verbose;                   $socket= FCGI::OpenSocket( $unixsocket, 10 );                   if( !$socket) {                            print"       Couldn't createsocket\n";                            addlog($logfile,"Couldn't create socket");                            exit1;                   }                   print"       Using UNIX socket$unixsocket\n" if $verbose;         }else {                   print"       Creating TCP/IPsocket\n" if $verbose;                   $portnumber= ":".$unixport;                   $socket= FCGI::OpenSocket( $unixport, 10 );                   if( !$socket ) {                            print"       Couldn't createsocket\n";                            addlog($logfile,"Couldn't create socket");                            exit1;                   }                   print" Using port $unixport\n" if $verbose;         }         addlog($logfile,"Socket created");          if( ! $filepid ) {                   print"\n\tERROR\t PID file must declared\n"                            ."\tuse $0 with option -pid filename\n\n";                   exit1;         }         print"       Using PID file$filepid\n" if $verbose;         addlog($logfile,"Using PID file $filepid");          my$pidnumber = $$;         $pidnumber> io($filepid);         print" PID number $$\n" if $verbose;         addlog($logfile,"PID number $pidnumber");        } sub addzero {         my($date) = shift;         if($date                   return"0$date";         }      return $date;} sub logformat {         my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$iddst) = localtime(time);         my$datestring;         $year+= 1900;         $mon++;         $mon  = addzero($mon);         $mday= addzero($mday);         $min  = addzero($min);         $datestring= "$year-$mon-$mday $hour:$min";         return($datestring);} sub addlog {         my($log_file, $log_message) = @_;         my$curr_time = logformat();         my$write_message = "[$curr_time]  $log_message";         $write_message>> io($log_file);         "\n">> io($log_file);} sub printerror {         my$message = @_;         print"\n   Nginx FastCGI\tERROR\n"                   ."\t $message\n\n";         exit1;} sub usage {         print"\n   Nginx FastCGI \n"                   ."\n\tusage: $0 [-h] -S string -P int\n"                   ."\n\t-h\t\t: this (help) message"                   ."\n\t-S path\t\t: path for UNIX socket"                   ."\n\t-P port\t\t: port number"                   ."\n\t-p file\t\t: path for pid file"                   ."\n\t-l file\t\t: path for logfile"                   ."\n\n\texample: $0 -S /var/run/nginx-perl_cgi.sock -l/var/log/nginx/nginx-cfgi.log -pid /var/run/nginx-fcgi.pid\n\n";         exit1;}  init;#END() { } BEGIN() { }*CORE::GLOBAL::exit = sub { die"fakeexit\nrc=".shift()."\n"; }; eval q{exit};if ($@) {         exitunless $@ =~ /^fakeexit/;} ; # fork partmy $pid = fork(); if( $pid == 0 ) {         &main;         exit0;} print " Forking worker processwith PID $pid\n" if $verbose;addlog($logfile, "Forking workerprocess with PID $pid");print " Update PID file$filepid\n" if $verbose;addlog($logfile, "Update PIDfile $filepid");$pid > io($filepid);print "       Worker process running.\n" if $verbose;addlog ($logfile, "Parentprocess $$ is exiting");exit 0; sub main {         $request= FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket );         if($request) { request_loop()};                   FCGI::CloseSocket($socket );} sub request_loop {         while($request->Accept() >= 0 ) {                   #processing any STDIN input from WebServer (for CGI-POST actions)                   $stdin_passthrough= '';                   $req_len= 0 + $req_params{'CONTENT_LENGTH'};                   if(($req_params{'REQUEST_METHOD'} eq 'POST') && ($req_len != 0) ){                            while($req_len) {                                     $stdin_passthrough.= getc(STDIN);                                     $req_len--;                                  }                   }                   # running the cgi app                   if( (-x $req_params{SCRIPT_FILENAME}) &&                            (-s$req_params{SCRIPT_FILENAME}) &&                            (-r$req_params{SCRIPT_FILENAME})                   ){                            foreach$key ( keys %req_params){                                     $ENV{$key}= $req_params{$key};                            }                            if( $verbose ) {                                     addlog($logfile,"running $req_params{SCRIPT_FILENAME}");                            }                            #http://perldoc.perl.org/perlipc.html#Safe-Pipe-Opens                            #                            open$cgi_app, '-|', $req_params{SCRIPT_FILENAME}, $stdin_passthrough orprint("Content-type: text/plain\r\n\r\n"); print "Error: CGI appreturned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n"; #addlog($logfile, "Error: CGI app returned no output - Executing$req_params{SCRIPT_FILENAME} failed !");                                                       if($cgi_app) {                                     print;                                     close$cgi_app;                            }                   }else {                            print("Content-type:text/plain\r\n\r\n");                            print"Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or isnot executable by this process.\n";                            addlog($logfile,"Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or isnot executable by this process.");                   }         }} nginx的配置        location ~ .*\.pl$ {                  fastcgi_pass  unix:/usr/local/nginx/logs/perl-fcgi.sock;                  fastcgi_index index.pl;                  fastcgi_param SCRIPT_FILENAME  /usr/local/nagios/sbin$fastcgi_script_name;                  include fastcgi.conf;          } 启动脚本为: Vi /usr/local/nginx/start_perl_cgi.sh #!/bin/bash   #set -x   dir=/usr/local/nginx       stop ()   {   #pkill -f  $dir/perl-fcgi.pl   kill $(cat $dir/logs/perl-fcgi.pid)   rm $dir/logs/perl-fcgi.pid 2>/dev/null   rm $dir/logs/perl-fcgi.sock2>/dev/null   echo "stop perl-fcgi done"  }       start ()   {   rm $dir/now_start_perl_fcgi.sh2>/dev/null       chown nobody.root $dir/logs   echo "$dir/perl-fcgi.pl -l$dir/logs/perl-fcgi.log -pid $dir/logs/perl-fcgi.pid -S$dir/logs/perl-fcgi.sock" >>$dir/now_start_perl_fcgi.sh       chown nobody.nobody$dir/now_start_perl_fcgi.sh   chmod u+x $dir/now_start_perl_fcgi.sh       sudo -u nobody$dir/now_start_perl_fcgi.sh   echo "start perl-fcgi done"  }       case $1 in  stop)   stop   ;;   start)   start   ;;   restart)   stop   start   ;;   esac
10-24 22:49
查看更多