nginx + fcgiwrap でcgiを動かす



nginxで小物のperlやpythonプログラムを動かすために、
Simple CGI support for Nginx (fcgiwrap)
を設定したときの作業内容です。


fcgiwrapをmakeするとき、


fcgi_stdio.h: そのようなファイルやディレクトリはありません


というエラーメッセージと共にビルドに失敗しました。
まずは、fastcgiのソースを取得し展開します。



#cd /usr/local/src
#wget http://www.fastcgi.com/dist/fcgi.tar.gz
#tar zxvf fcgi-2.4.0.tar.gz
#cd fcgi-2.4.0
#./configure
#make
#make install




次に、fcgiwrapのインストールを行います。


#wget http://github.com/gnosek/fcgiwrap/tarball/master
#tar zxvf gnosek-fcgiwrap-86921709962b95d4c7bf65c1c409c9809bf2e357.tar.gz
#cd gnosek-fcgiwrap-86921709962b95d4c7bf65c1c409c9809bf2e357
#make
#make install

[ -f /usr/local/bin/fcgiwrap ] && mv /usr/local/bin/fcgiwrap /usr/local/bin/fcgiwrap~
make: *** [install] エラー 1



こんな感じで、エラーが発生します。

注意点として、
・./configureはありません。
・make install はバイナリの移動に失敗します。

コンパイルは完了しているので手動でコピーしました。


#cp fcgiwrap /usr/local/bin/



※ここの作業は環境により異なります。

私はたまたまPythonをインストールしており、/usr/local/binのライブラリを
ロードするようにしていました。


#vi /etc/ld.so.conf.d/python-2.5.4.conf
/usr/local/bin



そのため、設定読み直しだけでfcgiのライブラリを読み込めましたが、


#vi /etc/ld.so.conf.d/fcgi.conf
/usr/local/bin


というファイルを作成した後に


#ldconfig


としてやる必要がありそうです。


次に、nginxの設定ファイルにcgiを起動する設定を行います。


###cgiに渡すパラメータファイルの保管先を作成
#mkdir /usr/local/nginx/conf

###設定ファイルをコピー
#cp /usr/local/nginx/fastcgi_params /usr/local/nginx/conf/

###nginxの設定ファイルを編集
#vi /usr/local/nginx/nginx.conf
location ~ ^/cgi-bin/.*\.cgi$
{
    fastcgi_pass    unix:/tmp/cgi.sock;
    fastcgi_read_timeout    5m;
    fastcgi_index    index.cgi;
    include    conf/fastcgi_params;
}


cgi-bin/*.cgiへのアクセスを/tmp/cgi.sockに渡すようにしてやります。


cgi.sockを作成し、fcgiwrapへの仲介役を行うperlスクリプトを作成します。



#vi /usr/local/nginx/fcgi.pl

#!/usr/bin/perl
use strict;
use warnings FATAL => qw( all );

use IO::Socket::UNIX;

my $bin_path = '/usr/local/bin/fcgiwrap';
my $socket_path = $ARGV[0] || '/tmp/cgi.sock';
my $num_children = $ARGV[1] || 1;

close STDIN;

unlink $socket_path;
my $socket = IO::Socket::UNIX->new(
    Local => $socket_path,
    Listen => 100,
);

die "Cannot create socket at $socket_path: $!\n" unless $socket;

for (1 .. $num_children) {
    my $pid = fork;
    die "Cannot fork: $!" unless defined $pid;
    next if $pid;

    exec $bin_path;
    die "Failed to exec $bin_path: $!\n";
}


###作成したファイルに実行権限付与
#chmod +x fcgi.pl

###実行
#./fcgi.pl



これで、/tmp/cgi.sockが作成されているはずです。


※これが正しいのか不明ですが、このままだとnginxのログに


connect() to unix:/tmp/cgi.sock failed (13: Permission denied) while connecting to upstream


と出力され、動いてくれませんでした。

とりあえずの対策として、


#chmod 777 /tmp/cgi.sock


を実行して逃げています。



次に、テスト用のプログラムを作成します。


#mkdir /usr/local/nginx/html/cgi-bin
#vi /usr/local/nginx/html/cgi-bin/test.cgi

#!/usr/bin/env perl
print "Content-type: text/html\n\n";
print "<html><head><title>Hello World</title></head>\n";
print "<body>\n";
print "<h2>Hello, world!</h2>\n";
print "</body></html>\n";

#chmod +x /usr/local/nginx/html/cgi-bin/test.cgi


/sbin/nginxを実行して、
http://www.example.com/cgi-bin/test.cgiにアクセスすると、
Hello, world!とPerlのプログラムが答えてくれます。



完全に理解できてはいないのですが、

・nginxはcgiのリクエストを/tmp/cgi.sockにリダイレクト
・fcgc.plが/tmp/cgi.sockへの処理要求をfcgiwrapにリダイレクト
・fcgiwrapでtest.cgiの処理を実行する。

という流れになるかと思います。


【参考URL】
Simple CGI support for Nginx (fcgiwrap)
NginxFcgiExample
nginx-fcgi
FastCGIのインストール(CentOS+Apache2)



もどる