zoukankan      html  css  js  c++  java
  • nginx支持cgi


    nginx支持cgi

     

    想在现有环境LNMP上部署一下Nagios,但是发现默认情况下Nginx自身是无法解析外部CGI程序的,于是官方给出了一个这样的做法http://wiki.nginx.org/NginxSimpleCGI,通过研究发现有两种方式可以实现让nginx支持cgi,两种方式都需要安装那几包.下面分别来介绍:

     

    第一种方式操作步骤:

    一、安装perl

    perl-FCGIperl-FCGI-ProcManagerperl-IO-ALL(如下文件均可以去http://search.cpan.org下载)

    #wget http://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

     

    #wget http://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< $req_len ) {

            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, "<&CHILD_RD");

            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内修改

     

     

    三、配置Nginx

    Nginx配置如下

    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 "<html><body>Hello, world.</body></html>";

     

    然后打开浏览器访问http://localhost/test.cgi,如果出现内容为Hello,world.则说明配置成功。

     

     

     

    第二种方式:

    vi /usr/local/nginx/perl-fcgi.pl

     

    #!/usr/bin/perl

    #

    #       author               Daniel Dominik Rudnicki

    #       thanks to:         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";

                       exit 1;

             }

     

            if ( ! $logfile ) {

                       print "\n\tERROR\t log file must declared\n"

                                . "\tuse $0 with option -l filename\n\n";

                       exit 1;

             }

             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";

                       exit 1;

             }

     

             if ($unixsocket) {

                       print "       Daemon listening at UNIX socket $unixsocket\n" if $versbose;

                       addlog($logfile, "Deamon listening at UNIX socket $unixsocket");

             } else {

                       print "       Daemon listening at TCP/IP socket *:$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.");

                       exit 1;

             }

     

             if ( $unixsocket ) {

                       print "       Creating UNIX socket\n" if $verbose;

                       $socket = FCGI::OpenSocket( $unixsocket, 10 );

                       if ( !$socket) {

                                print "       Couldn't create socket\n";

                                addlog($logfile, "Couldn't create socket");

                                exit 1;

                       }

                       print "       Using UNIX socket $unixsocket\n" if $verbose;

             } else {

                       print "       Creating TCP/IP socket\n" if $verbose;

                       $portnumber = ":".$unixport;

                       $socket = FCGI::OpenSocket( $unixport, 10 );

                       if ( !$socket ) {

                                print "       Couldn't create socket\n";

                                addlog($logfile, "Couldn't create socket");

                                exit 1;

                       }

                       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";

                       exit 1;

             }

             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 < 10) {

                       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";

             exit 1;

    }

     

    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";

             exit 1;

    }

     

     

    init;

    #

    END() { } BEGIN() { }

    *CORE::GLOBAL::exit = sub { die "fakeexit\nrc=".shift()."\n"; }; eval q{exit};

    if ($@) {

             exit unless $@ =~ /^fakeexit/;

    } ;

     

    # fork part

    my $pid = fork();

     

    if( $pid == 0 ) {

             &main;

             exit 0;

    }

     

    print " Forking worker process with PID $pid\n" if $verbose;

    addlog($logfile, "Forking worker process with PID $pid");

    print " Update PID file $filepid\n" if $verbose;

    addlog($logfile, "Update PID file $filepid");

    $pid > io($filepid);

    print "       Worker process running.\n" if $verbose;

    addlog ($logfile, "Parent process $$ 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 or print("Content-type: text/plain\r\n\r\n"); print "Error: CGI app returned 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 <$cgi_app>;

                                         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 is not executable by this process.\n";

                                addlog($logfile, "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not 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.sock 2>/dev/null 

     

     echo "stop perl-fcgi done"

     

     } 

     

       

     

     start () 

     

     { 

     

     rm $dir/now_start_perl_fcgi.sh 2>/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

  • 相关阅读:
    爬取校园新闻首页的新闻的详情,使用正则表达式,函数抽离
    网络爬虫基础练习
    Mysql 使用 select into outfile
    Mysql 使用CMD 登陆
    使用Clean() 去掉由函数自动生成的字符串中的双引号
    Get Resultset from Oracle Stored procedure
    获取引用某个主键的所有外键的表
    Entity Framework 丢失数据链接的绑定,在已绑好的EDMX中提示“Choose Your Data Connection”
    添加MySql Metat Database 信息
    at System.Data.EntityClient.EntityConnection.GetFactory(String providerString)
  • 原文地址:https://www.cnblogs.com/feihongwuhen/p/7169892.html
Copyright © 2011-2022 走看看