Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3049395
  • 博文数量: 535
  • 博客积分: 15788
  • 博客等级: 上将
  • 技术积分: 6507
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-07 09:11
文章分类

全部博文(535)

文章存档

2016年(1)

2015年(1)

2014年(10)

2013年(26)

2012年(43)

2011年(86)

2010年(76)

2009年(136)

2008年(97)

2007年(59)

分类: 系统运维

2009-07-29 10:25:06

首先:有三种方式(三个不同的脚本)搭建fastcgi环境,第二种,在运行时,nginx的error里会报错,但是不影响使用FastCGI sent in stderr: "Bad file descriptor at /EBS/fcgi.pl line 125",第二种脚本的优点是可以起多个进程(process),第三个脚本的优点是配置简单。

第二种方法的官方文档:

方法一
参考:
1、安装FCGI模块:
到网站上下载FCGI模块:
wget CPAN/authors/id/S/SK/SKIMO/FCGI-0.67.tar.gz

 tar -zxvf FCGI-0.67.tar.gz. 
 cd FCGI-0.67 
 perl Makefile.PL
 make 
 make install

2、安装 IO 和 IO::ALL模块
下载:
wget CPAN/authors/id/G/GB/GBARR/IO-1.25.tar.gz
CPAN/authors/id/I/IN/INGY/IO-All-0.39.tar.gz

安装:
tar -xvzf IO-1.25.tar.gz
cd IO-1.25
 perl Makefile.PL
 make 
 make install

tar -xvzf IO-All-0.39.tar.gz
cd IO-ALL-0.39
 perl Makefile.PL
 make 
 make install

3、如果需要,安装perl-Getopt和 perl-Socket

4、perl cgi脚本

文件:nginx-fcgi.rar
大小:2KB
下载:下载


或从下面的地址下载

5、启动cgi脚本 (nobody为nginx的运行用户)
vi start_perl_cgi.sh

#!/bin/bash

#set -x


if [[ $# != 1 ]];then

echo "usage $0 start|stop|restart"

exit 1

fi


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


启动
./start_perl_cgi.sh start

6为Nginx添加FCGI支持(以安装nagios为例)

        location ~* .*\.cgi$

                {

                     rewrite ^/nagios/cgi-bin/(.*)\.cgi /$1.cgi break;

                      include perl_fcgi.conf;

        }

重写请求cgi的url为cgi的文件名,组成下面的
CRIPT_FILENAMEvi perl_fcgi.conf

gzip off; #gzip makes scripts feel slower since they have to complete before getting gzipped
fastcgi_pass unix:/usr/local/nginx/logs/perl-fcgi.sock;
fastcgi_index index.cgi;

fastcgi_param SCRIPT_FILENAME /usr/local/nagios/sbin$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_script_name就是访问的URL中的URI
测试页
#!/usr/bin/perl -w
print "Content-type: text/plain\r\n\r\n";#发送头信息
print "test";

记得一定要给nginx发送头信息 不然会报504错误的。


另:

cgi-bin存在于html目录下时(不是为了部署nagios)

nginx.conf更改下面的部分:

location ~* .*\.cgi$
                {
                        include perl_fcgi.conf;
                }

perl_fcgi.conf更改下面的部分:

gzip off; #gzip makes scripts feel slower since they have to complete before getting gzipped
fastcgi_pass unix:/usr/local/nginx/logs/perl-fcgi.sock;
fastcgi_index index.cgi;

fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name;




方法二
1、安装FCGI模块:
到网站上下载FCGI模块:
wget CPAN/authors/id/S/SK/SKIMO/FCGI-0.67.tar.gz

 tar -zxvf FCGI-0.67.tar.gz. 
 cd FCGI-0.67 
 perl Makefile.PL
 make 
 make install

也可以这样安装:perl -MCPAN -e 'install FCGI'
(我在使用这种方法时,没有找到FCGI模块)


2、安装FCGI-ProcManager模块:
 wget CPAN/authors/id/G/GB/GBJK/FCGI-ProcManager-0.19.tar.gz
 tar -xvzf FCGI-ProcManager-0.19.tar.gz
 perl Makefile.PL
 make
 make install

3、Fastcgi 启动脚本
fcgi.pl

  1. #!/usr/bin/perl -w
  2. use FCGI;
  3. use Socket;
  4. use FCGI::ProcManager;
  5. sub shutdown { FCGI::CloseSocket($socket)exit}
  6. sub restart { FCGI::CloseSocket($socket)&main; }
  7. use sigtrap 'handler', \&shutdown, 'normal-signals';
  8. use sigtrap 'handler', \&restart, 'HUP';
  9. require 'syscall.ph';
  10. use POSIX qw(setsid);
  11.  
  12. #&daemonize; we don't daemonize when running under runsv
  13. #this keeps the program alive or something after exec'ing perl scripts
  14. END() { }
  15. BEGIN() { }
  16. {
  17. no warnings;
  18. *CORE::GLOBAL::exit = sub { die "fakeexit\nrc=" . shift() . "\n"};
  19. };
  20. eval q{exit};
  21. if ($@) {
  22. exit unless $@ =~ /^fakeexit/;
  23. }
  24. &main;
  25.  
  26. sub daemonize() {
  27. chdir '/' or die "Can't chdir to /: $!";
  28. defined( my $pid = fork ) or die "Can't fork: $!";
  29. exit if $pid;
  30. setsid() or die "Can't start a new session: $!";
  31. umask 0;
  32. }
  33.  
  34. sub main {
  35. #如果使用 IP sockets
  36. #$socket = FCGI::OpenSocket( "127.0.0.1:8999", 10 );
  37. #如果使用 UNIX sockets
  38. #$socket = FCGI::OpenSocket( "/var/run/perl_cgi-dispatch.sock", 10 );
  39.  
  40. #foreach $item (keys %ENV) { delete $ENV{$item}; }
  41. #设置fastcgi进程数,默认四个
  42. my $n_processes = $ENV{FCGI_NPROCESSES} || 4;
  43. $proc_manager = FCGI::ProcManager->new( {n_processes => $n_processes} );
  44. #使用unix socket
  45. $socket = FCGI::OpenSocket( "$ENV{FCGI_SOCKET_PATH}"10 );
  46. #设置Socket权限
  47. chmod 0777$ENV{FCGI_SOCKET_PATH};
  48.  
  49. #use UNIX sockets - user running this script must have w access to the 'nginx' folder!!
  50. $request =
  51. FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params$socket,
  52. &FCGI::FAIL_ACCEPT_ON_INTR );
  53. $proc_manager->pm_manage();
  54. if ($request) { request_loop() }
  55. FCGI::CloseSocket($socket);
  56. }
  57.  
  58. sub request_loop {
  59. while ( $request->Accept() >0 ) {
  60. $proc_manager->pm_pre_dispatch();
  61.  
  62. #processing any STDIN input from WebServer (for CGI-POST actions)
  63. $stdin_passthrough = '';
  64. { no warnings; $req_len = 0 + $req_params{'CONTENT_LENGTH'}};
  65. if ( ( $req_params{'REQUEST_METHOD'} eq 'POST' ) && ( $req_len !0 ) )
  66. {
  67. my $bytes_read = 0;
  68. while ( $bytes_read < $req_len ) {
  69. my $data = '';
  70. my $bytes = read( STDIN$data( $req_len - $bytes_read ) );
  71. last if ( $bytes == 0 || !defined($bytes) );
  72. $stdin_passthrough .= $data;
  73. $bytes_read += $bytes;
  74. }
  75. }
  76.  
  77. #running the cgi app
  78. if (
  79. ( -x $req_params{SCRIPT_FILENAME} ) && #can I execute this?
  80. ( -s $req_params{SCRIPT_FILENAME} ) && #Is this file empty?
  81. ( -r $req_params{SCRIPT_FILENAME} ) #can I read this file?
  82. )
  83. {
  84. pipe( CHILD_RD, PARENT_WR );
  85. pipe( PARENT_ERR, CHILD_ERR );
  86. my $pid = open( CHILD_O, "-|" );
  87. unless ( defined($pid) ) {
  88. print("Content-type: text/plain\r\n\r\n");
  89. print
  90. "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n";
  91. next;
  92. }
  93. $oldfh = select(PARENT_ERR);
  94. $| = 1;
  95. select(CHILD_O);
  96. $| = 1;
  97. select($oldfh);
  98. if ( $pid > 0 ) {
  99. close(CHILD_RD);
  100. close(CHILD_ERR);
  101. print PARENT_WR $stdin_passthrough;
  102. close(PARENT_WR);
  103. $rin = $rout = $ein = $eout = '';
  104. vec( $rinfileno(CHILD_O)1 ) = 1;
  105. vec( $rinfileno(PARENT_ERR)1 ) = 1;
  106. $ein = $rin;
  107. $nfound = 0;
  108.  
  109. while ( $nfound =
  110. select( $rout = $rinundef$ein = $eout10 ) )
  111. {
  112. die "$!" unless $nfound !-1;
  113. $r1 = vec( $routfileno(PARENT_ERR)1 ) == 1;
  114. $r2 = vec( $routfileno(CHILD_O)1 ) == 1;
  115. $e1 = vec( $eoutfileno(PARENT_ERR)1 ) == 1;
  116. $e2 = vec( $eoutfileno(CHILD_O)1 ) == 1;
  117.  
  118. if ($r1) {
  119. while ( $bytes = read( PARENT_ERR, $errbytes4096 ) ) {
  120. print STDERR $errbytes;
  121. }
  122.  
  123. if ($!) {
  124. $err = $!;
  125. die $!;
  126. vec( $rinfileno(PARENT_ERR)1 ) = 0
  127. unless ( $err == EINTR or $err == EAGAIN );
  128. }
  129. }
  130. if ($r2) {
  131. while ( $bytes = read( CHILD_O, $s4096 ) ) {
  132. print $s;
  133. }
  134. if ( !defined($bytes) ) {
  135. $err = $!;
  136. die $!;
  137. vec( $rinfileno(CHILD_O)1 ) = 0
  138. unless ( $err == EINTR or $err == EAGAIN );
  139. }
  140. }
  141. last if ( $e1 || $e2 );
  142. }
  143. close CHILD_RD;
  144. close PARENT_ERR;
  145. waitpid( $pid0 );
  146. } else {
  147. foreach $key ( keys %req_params ) {
  148. $ENV{$key} = $req_params{$key};      
  149. }
  150.  
  151. # cd to the script's local directory
  152. if ( $req_params{SCRIPT_FILENAME} =~ /^(.*)\/[^\/]+$/ ) {
  153. chdir $1;
  154. }
  155. close(PARENT_WR);
  156.  
  157. #close(PARENT_ERR);
  158. close(STDIN);
  159. close(STDERR);
  160.  
  161. #fcntl(CHILD_RD, F_DUPFD, 0);
  162. syscall( &SYS_dup2, fileno(CHILD_RD)0 );
  163. syscall( &SYS_dup2, fileno(CHILD_ERR)2 );
  164.  
  165. #open(STDIN, "<&CHILD_RD");
  166. exec( $req_params{SCRIPT_FILENAME} );
  167. die("exec failed");
  168. }
  169. } else {
  170. print("Content-type: text/plain\r\n\r\n");
  171. print
  172. "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n";
  173. }
  174. }
  175. }



使用下面的脚本启动
vi start_fcgi.sh
  1. export FCGI_SOCKET_PATH="/tmp/perl_fcgi.socket"
  2. export FCGI_NPROCESSES=4
  3. ./fcgi.pl &

4、为Nginx添加FCGI支持(以安装nagios为例)

location ~* .*\.cgi$
                {
                      rewrite ^/nagios/cgi-bin/(.*)\.cgi /$1.cgi break;
                        include perl_fcgi.conf;
                }

将请求cgi的url由/nagios/cgi-bin/*.cgi 重写为/*.cgi,这样,即下面的fastcgi_param中的$fastcgi_script_name,这样,可以正确的拼出cgi文件的路径。
vi perl_fcgi.conf

gzip off; #gzip makes scripts feel slower since they have to complete before getting gzipped
fastcgi_pass unix:/tmp/perl_fcgi.socket;
fastcgi_index index.cgi;

fastcgi_param SCRIPT_FILENAME /usr/local/nagios/sbin$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-wrapper.pl脚本
下载地址:
或从下面下载,记得修改扩展名。
添加可执行权限,启动:
sudo -u nobody ./fastcgi-wrapper.pl >>log.cgi 2>&1 &
log.cgi中记录错误信息。

关于:bind/listen: Permission denied
检查sock文件所在目录对于nobody是否有写的权限

添加nginx配置:
  1. location ~ \.cgi$ {
  2. fastcgi_pass unix:/var/run/nginx/perl_cgi-dispatch.sock;
  3. fastcgi_index index.cgi;
  4. fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  5. include fastcgi_params;
  6. }
测试页面:
#!/usr/bin/perl -w
print "Content-type: text/plain\r\n\r\n";#发送头信息
print "test";

记得一定要给nginx发送头信息 不然会报504错误的。

                     


阅读(4742) | 评论(6) | 转发(0) |
给主人留下些什么吧!~~

locale2009-08-11 18:38:45

晕了,虽然按照第一种方法配置出来了,但还是没明白是怎么回事,请多指教,随便转载了一下,方便学习,http://www.hardwork.cn,还是要感谢一下。