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

  • 相关阅读:
    IOS 线程 +并发
    ios
    ios
    ios uitableviewcell动态计算高度
    ios 画圆环进度条
    ios -几种常见定时器
    ios 加载本地html css文件 ps:css和html必须在同一文件夹下面
    UISegmentedControl 分段器加载不同的viewcontroller
    iOS ----Pods-resources.sh Permission denied
    UIView的layout(布局)与draw(绘图)
  • 原文地址:https://www.cnblogs.com/feihongwuhen/p/7169892.html
Copyright © 2011-2022 走看看