为了Awstats给Nginx添加FastCGI方式的Perl支持
有个应用(awstats)需要Perl脚本支持,但是用的Nginx服务器,对Perl支持不好,于是通过FastCGI方式来使用Perl。
首先安装Perl的FCGI模块
-
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
还可以使用如下方法安装:
perl -MCPAN -e 'install FCGI'
安装FCGI-ProcManager
-
wget http://search.cpan.org/CPAN/authors/id/G/GB/GBJK/FCGI-ProcManager-0.18.tar.gz
-
tar -xzxf FCGI-ProcManager-0.18.tar.gz
-
cd FCGI-ProcManager-0.18
-
perl Makefile.PL
-
make
-
make install
Perl的FastCGI启动脚本
参考这篇文章 http://bbs.chinaunix.net/archiver/?tid-1224968.html
vi fcgi_perl
-
#!/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 {
-
#如果使用 IP sockets
-
#$socket = FCGI::OpenSocket( "127.0.0.1:8999", 10 );
-
#如果使用 UNIX sockets
-
#$socket = FCGI::OpenSocket( "/var/run/perl_cgi-dispatch.sock", 10 );
-
-
#foreach $item (keys %ENV) { delete $ENV{$item}; }
-
#设置fastcgi进程数,默认四个
-
my $n_processes = $ENV{FCGI_NPROCESSES} || 4;
-
$proc_manager = FCGI::ProcManager->new( {n_processes => $n_processes} );
-
#使用unix socket
-
$socket = FCGI::OpenSocket( "$ENV{FCGI_SOCKET_PATH}", 10 );
-
#设置Socket权限
-
chmod 0777, $ENV{FCGI_SOCKET_PATH};
-
-
; #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";
-
}
-
}
-
}
再设置启动的脚本
vi startfcgiperl
-
export FCGI_SOCKET_PATH="/tmp/perl_fcgi.socket"
-
export FCGI_NPROCESSES=4
-
./fcgi_perl &
为Nginx添加FastCGI的Perl支持
编辑 nginx.conf 脚本,添加如下内容
location ~* .*\.pl$ { include awstats.conf; } location /awstatsicon/ { alias /var/www/awstats-6.8/wwwroot/icon/; }
vi awstats.conf
fastcgi_pass unix:/tmp/perl_fcgi.socket; fastcgi_index awstats.pl; #fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; #fastcgi_param SCRIPT_FILENAME /var/www/awstats-6.8/wwwroot/cgi-bin$fastcgi_script_name; fastcgi_param SCRIPT_FILENAME /var/www/awstats-6.8/wwwroot/cgi-bin/awstats.pl; 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;
配置Awstats
运行 /var/www/awstats-6.8/tools/awstats_configure.pl 设置好一些变量
mkdir -p /etc/awstats cp /var/www/awstats-6.8/wwwroot/awstats.model.conf /etc/awstats/awstats.my.site.com.conf
使用 vi /etc/awstats.my.site.com.conf 进行一些参数修改,设置icon目录,DirData数据存放目录,来源log日志文件路径等
使用 /var/www/awstats-6.8/tool/awstats_updateall.pl now -awstatsprog=/var/www/awstats-6.8/wwwroot/cgi-bin/awstats.pl 命令进行初始数据更新
使用 http://my.site.com/awstats.pl 查看数据
后续
将 ./awstats_updateall.pl now -awstatsprog=/var/www/awstats-6.8/wwwroot/cgi-bin/awstats.pl 放到crontab 中做定时更新,可以做一个脚本和日志文件的处理一起做。
碰到问题
在使用unix socket时,碰到两个问题
1.写socket的目录没有写权限,添加上解决
2.nginx连不上socket, 看日志提示没有权限,在创建了socket后添加一句
chmod 0777, $ENV{FCGI_SOCKET_PATH};
问题解决。
遗留对awstats.pl访问密码限制问题尚未解决好。
解决 在 nginx 中按如下配置方式
location /awstats { root /var/www/awstats-6.8/; include awstats.conf; auth_basic "awstats"; auth_basic_user_file /var/www/.passwd; }
其中 将 awstats-6.8 目录下的 wwwroot 修改为 awstats, /var/www/.passwd 为访问目录要用来验证的账号密码文件,用apache的提供的工具htpasswd制作而成
Popularity: 7% [?]
Related
Comments
8 Responses to “为了Awstats给Nginx添加FastCGI方式的Perl支持”
[...] public links >> fastcgi 为了Awstats给Nginx添加FastCGI方式的Perl支持 First saved by RedFerryDwarf69 | 2 days ago MySQL, PHP with FastCGI and Joomla on Windows [...]
[...] August 31, 2008 — 为了Awstats给Nginx添加FastCGI方式的Perl支持 (1) [...]
有两点疑问:
1.
vi startfcgiperlexport FCGI_SOCKET_PATH=”/tmp/perl_fcgi.socket”
export FCGI_NPROCESSES=4
./fcgi_perl &
这里fcgi_perl会输出到到控制台上.
我使用1>/dev/null 2>&1 解决
2.
你的awstats能显示图片吗? 怎么解决的?
[Reply]
sunny Reply:
November 1st, 2008 at 5:15 pm
你可以尝试修改awstats.model.conf 中的 DirIcons路径设置,在配合Web服务器中的路径设置,可以达到显示图片目的
[Reply]
xi2008wang Reply:
November 3rd, 2008 at 12:26 am
多谢, 已解决.
我是按awstats官方文档将icon复制到了根目录
[Reply]
.pl 后面可以加参数吗?
[Reply]
sunny Reply:
November 8th, 2008 at 11:32 pm
什么意思?给 fcgi_perl 脚本加 命令行 参数 ?
[Reply]
就是在浏览器地址栏里:像这样的链接
http://sitename.com/xxx.pl?name=xxx&status=yyy&k=0
我试了一下,不加后面那些get的参数是没问题的,但是加上了就不行了。
[Reply]