Project

General

Profile

NginxへのPerl-CGIモジュールのインストール

  • 「Nginx(エンジンエックス)」でのCGIの利用に関するページです。

前提条件

  • CentOS 6.xでの実装を前提としています。
  • Nginxはリポジトリおよび本体を構築済みとします。
  • epelリポジトリを使用します。

インストール

  • epelを導入します。
    # wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
    # rpm -ivh epel-release-6-8.noarch.rpm
    
  • リポジトリを追加からfcgi-perlのパッケージをインストールします。
    # yum install --enablerepo=epel fcgi-perl
    

設定ファイル編集

  • 次の設定ファイルを編集します。(コメントアウトを外して微調整します)
    # vi /etc/nginx/conf.d/default.conf
    # ------------------------------------------------------
    server {
    ・・・中略
        location ~ \.cgi$ {
           gzip           off;
           fastcgi_pass   127.0.0.1:8999;
           include        fastcgi_params;
           fastcgi_index  index.cgi;
           fastcgi_param  DOCUMENT_ROOT /usr/share/nginx/html;
           fastcgi_param  SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
        }
    ・・・中略
    
  • ラッパースクリプトを作成します。
    # vi /usr/bin/fastcgi-wrapper.pl
    # ------------------------------------------------------
    #!/usr/bin/perl
    
    use FCGI;
    use Socket;
    use POSIX qw(setsid);
    
    require 'syscall.ph';
    
    &daemonize;
    
    #this keeps the program alive or something after exec'ing perl scripts
    END() { } BEGIN() { }
    *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:8999", 10 ); #use IP sockets
            $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) ){
                    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);
            my $pid = open(KID_TO_READ, "-|");
            unless(defined($pid)) {
                print("Content-type: text/plain\r\n\r\n");
                            print "Error: CGI app returned no output - ";
                            print "Executing $req_params{SCRIPT_FILENAME} failed !\n";
                next;
            }
            if ($pid > 0) {
                close(CHILD_RD);
                print PARENT_WR $stdin_passthrough;
                close(PARENT_WR);
    
                while(my $s = <KID_TO_READ>) { print $s; }
                close KID_TO_READ;
                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(STDIN);
                #fcntl(CHILD_RD, F_DUPFD, 0);
                syscall(&SYS_dup2, fileno(CHILD_RD), 0);
                #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 ";
                    print "exist or is not executable by this process.\n";
                }
    
            }
    }
    
  • 起動スクリプトを作成します。
    # vi /etc/init.d/perl-fastcgi
    # ------------------------------------------------------
    #!/bin/sh
    #
    # nginx – this script starts and stops the nginx daemon
    #
    # chkconfig: - 85 15
    # description: Nginx is an HTTP(S) server, HTTP(S) reverse \
    # proxy and IMAP/POP3 proxy server
    # processname: nginx
    # config: /opt/nginx/conf/nginx.conf
    # pidfile: /opt/nginx/logs/nginx.pid
    
    # Source function library.
    . /etc/rc.d/init.d/functions
    
    # Source networking configuration.
    . /etc/sysconfig/network
    
    # Check that networking is up.
    [ "$NETWORKING" = "no" ] && exit 0
    
    perlfastcgi="/usr/bin/fastcgi-wrapper.pl" 
    prog=$(basename perl)
    
    lockfile=/var/lock/subsys/perl-fastcgi
    
    start() {
        [ -x $perlfastcgi ] || exit 5
        echo -n $"Starting $prog: " 
        daemon $perlfastcgi
        retval=$?
        echo
        [ $retval -eq 0 ] && touch $lockfile
        return $retval
    }
    
    stop() {
        echo -n $"Stopping $prog: " 
        killproc $prog -QUIT
        retval=$?
        echo
        [ $retval -eq 0 ] && rm -f $lockfile
        return $retval
    }
    
    restart() {
        stop
        start
    }
    
    reload() {
        echo -n $”Reloading $prog: ”
        killproc $nginx -HUP
        RETVAL=$?
        echo
    }
    
    force_reload() {
        restart
    }
    rh_status() {
        status $prog
    }
    
    rh_status_q() {
        rh_status >/dev/null 2>&1
    }
    
    case "$1" in
        start)
            rh_status_q && exit 0
            $1
            ;;
        stop)
            rh_status_q || exit 0
            $1
            ;;
        restart)
            $1
            ;;
        reload)
            rh_status_q || exit 7
            $1
            ;;
        force-reload)
            force_reload
            ;;
        status)
            rh_status
            ;;
        condrestart|try-restart)
            rh_status_q || exit 0
            ;;
        *)
            echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" 
            exit 2
        esac
    
  • 実行権限を付与します。
    # chmod a+x /usr/bin/fastcgi-wrapper.pl
    # chmod a+x /etc/init.d/perl-fastcgi
    

動作確認

  • 次のコマンドが正しく実行されるかテストします。php-fpmが先に起動するようにします。
    # service perl-fastcgi start
    # service nginx restart
    
  • サンプルスクリプトを作成します。
    # vi /usr/share/nginx/html/index.cgi
    # ------------------------------------------------------
    #!/usr/bin/perl
    
    print "Content-type: text/html\n\n";
    print "<html><body>\n";
    
    print "<h1>CGIでの環境変数一覧</h1>\n";
    print "<hr>\n";
    
    print "<h3>環境変数の表示</h3>\n";
    foreach $key (sort keys %ENV) {
        print $key, " = ", $ENV{$key}, "<br>\n";
    }
    
    print "<hr><br>\n";
    print "このCGIのソース:<a href=env01.txt>env01.cgi</a><br>\n";
    print "</body></html>\n";
    
  • 実行権限を付与します。
    # chmod 755 /usr/share/nginx/html/index.cgi
    
  • ブラウザで次のアドレスへアクセスし、スクリプトの実行を確認します。
    http://192.168.34.61/index.cgi
    

自動起動設定

  • テストが正しく行えたら、自動起動を設定します
    # chkconfig perl-fastcgi on
    # chkconfig --list perl-fastcgi
    

 

戻る