服务器维护,服务器代维,安全设置,漏洞扫描,入侵检测服务

dirtysea 发表于 2011-11-1 12:46:07

nginx用fastcgi方式运行perl脚本

笔者的nginx安装目录为/opt/nginx虚拟机配置文件为/opt/nginx/conf/vhosts.conf目前php fast-cgi已支持以下操作均在su下完成=====================安装perl cgi模块
#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 安装FCGI-ProcManager:
#wget http://cpan.wenzk.com/authors/id/G/GB/GBJK/FCGI-ProcManager-0.19.tar.gz   
tar -xzxf FCGI-ProcManager-0.19.tar.gz
cd FCGI-ProcManager-0.19
perl Makefile.PL      
make && make install
===================先在/bin目录下放置一个perl写的分发器,取名叫perl-fcgivim /bin/perl-fcgi#!/usr/bin/perl -w    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);       #&daemonize; we don't daemonize when running under runsv    #this keeps the program alive or something after exec'ing perl scripts    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 {          $socket = FCGI::OpenSocket( "127.0.0.1:10081", 10 ); #use IP sockets        #$socket = FCGI::OpenSocket( "/var/run/nginx/perl_cgi-dispatch.sock", 10 );       #use UNIX sockets - user running this script must have w access to the 'nginx' folder!!        #foreach $item (keys %ENV) { delete $ENV{$item}; }        $proc_manager = FCGI::ProcManager->new( {n_processes => 5} );        #$socket = FCGI::OpenSocket( "/opt/nginx/fcgi/cgi.sock", 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 +x /bin/perl-fcgi
然后试试看能否启动
/bin/perl-fcgi &
若是成功则会出现以下信息
FastCGI: server (pid 21315): initialized
FastCGI: manager (pid 17915): server (pid 21315) started

如果遇到错误Can’t locate FCGI.pm,那么执行下面的命令
perl -MCPAN -e 'install FCGI'
perl -MCPAN -e 'install FCGI::ProcManager'
cd /usr/include; h2ph *.h */*.h
第一、二条命令是给perl安装FCGI模块,第三条是注册perl能识别的头文件,然后重新执行/bin/perl-fcgi, 如果正常的话,那么执行:
netstat -tunlp    (列表中应该出现)
tcp   0      0 127.0.0.1:10081      0.0.0.0:*      LISTEN      1004/perl-fcgi-pm
启用分发器
/bin/perl-fcgi > /dev/null 2>&1 &
将其写自启动(如rc.local)
echo "/bin/perl-fcgi > /dev/null 2>&1 &" >> /sbin/php-cgi.sh
上面的方式启动后perl-fcgi是以执行它的用户身份运行的,对于web程序来说这是很不利的。老外用perl写了一个脚本Noah Friedman可以用指定的用户来运行某个程序,源程序如下:vim /sbin/runas #!/bin/shexec ${PERL-perl} -Swx $0 ${1+"$@"}#!perl                # with --- run program with special properties # Copyright (C) 1995, 2000, 2002 Noah S. Friedman # Author: Noah Friedman <friedman@splode.com># Created: 1995-08-14 # $Id: with,v 1.12 2004/02/16 22:51:49 friedman Exp $ # This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2, or (at your option)# any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, you can either send email to this# program's maintainer or write to: The Free Software Foundation,# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. # Commentary: # TODO: create optional socket streams for stdin or stdout before invoking# subprocess. # Code: use Getopt::Long;use POSIX qw(setsid);use Symbol;use strict; (my $progname = $0) =~ s|.*/||;my $bgfn;my $bgopt = 0; my $opt_cwd;my $opt_egid;my $opt_euid;my $opt_gid;my $opt_groups;my @opt_include;my $opt_name;my $opt_pgrp;my $opt_priority;my $opt_root;my $opt_uid;my $opt_umask;my $opt_foreground = 0; sub err{my $fh = (ref ($_) ? shift : *STDERR{IO});print $fh join (": ", $progname, @_), "\n";exit (1);} sub get_includes{unshift @INC, @_;push (@INC,      "$ENV{HOME}/lib/perl",      "$ENV{HOME}/lib/perl/include"); eval { require "syscall.ph" } if defined $opt_groups;} sub numberp{defined $_ && $_ =~ m/^-?\d+$/o;} sub group2gid{my $g = shift;return $g if numberp ($g);my $gid = getgrnam ($g);return $gid if defined $gid && numberp ($gid);err ($g, "no such group");} sub user2uid{my $u = shift;return $u if numberp ($u);my $uid = getpwnam ($u);return $uid if defined $uid && numberp ($uid);err ($u, "no such user");} sub set_cwd{my $d = shift;chdir ($d) || err ("chdir", $d, $!);} sub set_egid{my $sgid = group2gid (shift);my $egid = $) + 0; $) = $sgid;err ($sgid, "cannot set egid", $!) if ($) == $egid && $egid != $sgid);} sub set_gid{my $sgid = group2gid (shift);my $rgid = $( + 0;my $egid = $) + 0; $( = $sgid;$) = $sgid;err ($sgid, "cannot set rgid", $!) if ($( == $rgid && $rgid != $sgid);err ($sgid, "cannot set egid", $!) if ($) == $egid && $egid != $sgid);} sub big_endian_p{my $x = 1;my @y = unpack ("c2", pack ("i", $x));return ($y == 1) ? 0 : 1;} # This function is more complex than it ought to be because perl does not# export the setgroups function.It exports the getgroups function by# making $( and $) return multiple values in the form of a space-separated# string, but you cannot *set* the group list by assigning those variables.# There is no portable way to determine what size gid_t is, so we must guess.sub set_groups{my @glist = sort { $a <=> $b } map { group2gid ($_) } split (/[ ,]/, shift); my $expected = join (" ", $(+0, reverse @glist);my @p = (big_endian_p() ? ("n", "N", "i") : ("v", "V", "i")); for my $c (@p)    {      err ("setgroups", $!)      if (syscall (&SYS_setgroups, @glist+0, pack ("$c*", @glist)) == -1);      return if ("$(" eq $expected);    }err ("setgroups", "Could not determine gid_t");} sub set_pgrp{setpgrp ($$, shift) || err ("setpgrp", $!);} sub set_priority{my $prio = shift () + 0;setpriority (0, 0, $prio) || err ("setpriority", $prio, $!);} sub set_root{my $d = shift;chroot ($d) || err ("chroot", $d, $!);chdir ("/");} sub set_euid{my $suid = user2uid (shift);my $euid = $>; $> = $suid;err ($suid, "cannot set euid", $!) if ($> == $euid && $euid != $suid);} sub set_uid{my $suid = user2uid (shift);my $ruid = $<;my $euid = $>; $< = $suid;$> = $suid;err ($suid, "cannot set ruid", $!) if ($< == $ruid && $ruid != $suid);err ($suid, "cannot set euid", $!) if ($> == $euid && $euid != $suid);} sub background{my $pid = fork;die "$@" if $pid < 0;if ($pid == 0)    {      # Backgrounded programs may expect to be able to read input from the      # user if stdin is a tty, but we will no longer have any job control      # management because of the double fork and exit.This can result in      # a program either blocking on input (if still associated with a      # controlling terminal) and stopping, or stealing input from a      # foreground process (e.g. a shell).So redirect stdin to /dev/null.      open (STDIN, "< /dev/null") if (-t STDIN);      return *STDERR{IO};    } exit (0) unless $opt_foreground;wait;exit ($?);} sub dosetsid{background ();setsid (); # dissociate from controlling terminalreturn *STDERR{IO};} sub daemon{# Don't allow any file descriptors, including stdin, stdout, or# stderr to be propagated to children.$^F = -1;dosetsid ();# Duped in case we've closed stderr but can't exec anything.my $saved_stderr = gensym;open ($saved_stderr, ">&STDERR");close (STDERR);close (STDOUT);close (STDIN);return $saved_stderr;} sub notty{# Don't allow any file descriptors other than stdin, stdout, or stderr to# be propagated to children.$^F = 2;dosetsid ();# Duped in case we've closed stderr but can't exec anything.my $saved_stderr = gensym;open ($saved_stderr, ">&STDERR");open (STDIN,"+</dev/null");open (STDERR, "+<&STDIN");open (STDOUT, "+<&STDIN");return $saved_stderr;} sub set_bg_option{my %bgfntbl =    ( 1 => \&background,      2 => \&daemon,      4 => \&notty,      8 => \&dosetsid,    ); $bgopt = $_;$bgfn= $bgfntbl{$bgopt};} sub parse_options{Getopt::Long::config (qw(bundling autoabbrev require_order));my $succ = GetOptions    ("h|help",          sub { usage () },   "c|cwd=s",         \$opt_cwd,   "d|display=s",   \$ENV{DISPLAY},   "H|home=s",      \$ENV{HOME},   "G|egid=s",      \$opt_egid,   "g|gid=s",         \$opt_gid,   "I|include=s@",    \@opt_include,   "l|groups=s",      \$opt_groups,   "m|umask=s",       \$opt_umask,   "n|name=s",      \$opt_name,   "P|priority=i",    \$opt_priority,   "p|pgrp=i",      \$opt_pgrp,   "r|root=s",      \$opt_root,   "U|euid=s",      \$opt_euid,   "u|uid=s",         \$opt_uid,    "f|fg|foreground", \$opt_foreground,    "b|bg|background", sub { set_bg_option (1); $opt_foreground = 0 },   "a|daemon|demon",sub { set_bg_option (2) },   "N|no-tty|notty",sub { set_bg_option (4) },   "s|setsid",      sub { set_bg_option (8) },    );usage () unless $succ; my $n = 0;do { $n++ if $bgopt & 1 } while ($bgopt >>= 1);err ("Can only specify one of --background, --daemon, --notty, or --setsid")    if ($n > 1);} sub usage{print STDERR "$progname: @_\n\n" if @_;print STDERR "Usage: $progname {options} \nOptions are:-h, --help            You're looking at it.-D, --debug         Turn on interactive debugging in perl.-I, --include   DIR   Include DIR in \@INC path for perl.                      This option may be specified multiple times to append                      search paths to perl. -d, --display   DISPRun with DISP as the X server display.-H, --home      HOMESet \$HOME.-n, --name      ARGV0 Set name of running program (argv). -c, --cwd       DIR   Run with DIR as the current working directory.                      This directory is relative to the root directory as                      specified by \`--root', or \`/'.-r, --root      ROOTSet root directory (via \`chroot' syscall) to ROOT. -G, --egid      EGIDSet \`effective' group ID.-g, --gid       GID   Set both \`real' and \`effective' group ID.-l, --groups    GLIST Set group list to comma-separated GLIST.-U, --euid      EUIDSet \`effective' user ID.-u, --uid       UID   Set both \`real' and \`effective' user ID. -m, --umask   UMASK Set umask.-P, --priorityNICESet scheduling priority to NICE (-20 to 20).-p, --pgrp      PGRPSet process group. The following options cause the resulting process to be backgroundedautomatically but differ in various ways: -b, --background      Run process in background.This is the default with                      the --daemon, --no-tty, and --setsid options. -f, --foreground      Do not put process into the background when using                      the --daemon, --no-tty, and --setsid options.                      In all other cases the default is to remain in the                      foreground. -a, --daemon          Run process in \"daemon\" mode.                      This closes stdin, stdout, and stderr, dissociates                      the process from any controlling terminal, and                      backgrounds the process. -N, --no-tty          Run process in background with no controlling                      terminal and with stdin, stdout, and stderr                      redirected to /dev/null. -s, --setsid          Dissociate from controlling terminal.                      This automatically backgrounds the process but                      does not redirect any file descriptors.\n";exit (1);} sub main{parse_options ();usage () unless @ARGV; get_includes (@opt_include); umask      (oct ($opt_umask)) if defined $opt_umask;set_gid      ($opt_gid)         if defined $opt_gid;set_egid   ($opt_egid)      if defined $opt_egid;set_groups   ($opt_groups)      if defined $opt_groups;set_root   ($opt_root)      if defined $opt_root;set_cwd      ($opt_cwd)         if defined $opt_cwd;set_priority ($opt_priority)    if defined $opt_priority;set_uid      ($opt_uid)         if defined $opt_uid;set_euid   ($opt_euid)      if defined $opt_euid; my $stderr = $bgfn ? &$bgfn () : *STDERR{IO}; my $runprog = $ARGV;if ($opt_name)    {      shift   @ARGV;      unshift @ARGV, $opt_name;    }local $^W = 0; # avoid implicit warnings from execexec ($runprog @ARGV) || err ($stderr, "exec", $runprog, $!);} main (); # local variables:# mode: perl# eval: (auto-fill-mode 1)# end: # with ends here chmod +x /sbin/runas我的vsftpd、nginx、php-fpm都是以www运行,则perl-cgi也用www运行
runas --daemon -g www -u www /bin/perl-fcgi echo "runas --daemon -g www -u www /bin/perl-fcgi" >> /sbin/php-cgi.sh配置nginx
vim /opt/nginx/conf/fcgi_perl.conf fastcgi_pass    127.0.0.1:10081;    fastcgi_index   index.cgi;    fastcgi_param SCRIPT_FILENAME   $document_root$fastcgi_script_name;    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 GATEWAY_INTERFACE CGI/1.1;    fastcgi_param SERVER_SOFTWARE   nginx;    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;    fastcgi_read_timeout            60; 下面是一个cgi虚拟机的配置示例 vim /opt/nginx/conf/nginx.confserver {                 listen             80;                 server_name      www.it-dw.net;                 index            index.cgi             root               /var/www;              location ~ .*\.cgi?$                        {                           include fcgi_perl.conf;                        }             }   }
service nginx restart
页: [1]
查看完整版本: nginx用fastcgi方式运行perl脚本