Nginx : exécution FastCGI Perl

Boris HUISGEN
|
Je vous joins ici la dernière version des scripts que j’utilise pour permettre l’exécution Perl en FastCGI avec Nginx (pour SmokePing, BackupPC, etc …)
Le script du démon Perl fcgi-perl.pl est à adapter à votre environnement système (utilisateur d’exécution, chemin de la socket UNIX). Le script de démarrage est à présent intégrable avec Heartbeat/Corosync …
Dépendances logicielles
root@muse:~# aptitude install libfcgi-perl libfile-pid-perl
Script FastCGI Perl
root@muse:~# cat /etc/nginx/fcgi-perl.pl
#!/usr/bin/perl
#
# FastCGI perl daemon
#
# Boris HUISGEN <bhuisgen@hbis.fr>
#
my ($pid_file) = "/var/run/fcgi-perl.pid"; # PID filename
my ($socket_file) = "/var/run/fcgi-perl.sock"; # UNIX socket filename
my ($socket_backlog) = 10; # socket backlog
my ($socket_uid) = 33; # socket UID
my ($socket_gid) = 33; # socket GID
my ($socket_perms) = 0600; # socket permissions
#
# script
#
use File::Pid;
use FCGI;
use Socket;
use POSIX qw(setsid);
require 'syscall.ph';
my ($pid_fd);
&daemonize;
*CORE::GLOBAL::exit = sub { die "fakeexit\nrc=".shift()."\n"; };
eval q{exit};
if ($@) {
exit unless $@ =~ /^fakeexit/;
};
&main;
sub cleanup() {
$pid_fd->remove if defined $pid_fd;
unlink($socket_file);
}
sub daemonize() {
chdir '/' or die "Failed to chdir to /: $!";
defined(my $pid = fork) or die "Failed to fork: $!";
exit if $pid;
setsid or die "Failed to start a new session: $!";
umask 0022;
$pid_fd = File::Pid->new({
file => $pid_file,
});
if ($pid_fd->running) { die "Instance already running" };
$pid_fd->write;
}
sub main {
$socket = FCGI::OpenSocket($socket_file, $socket_backlog);
$request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket);
chown($socket_uid, $socket_gid, $socket_file);
chmod($socket_perms, $socket_file);
if ($request) {
request_loop()
};
FCGI::CloseSocket($socket);
}
sub request_loop {
while($request->Accept() >= 0) {
$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;
}
}
if ( (-x $req_params{SCRIPT_FILENAME}) &&
(-s $req_params{SCRIPT_FILENAME}) &&
(-r $req_params{SCRIPT_FILENAME}) ){
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 - 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};
}
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 exist or is not executable by this process.\n";
}
}
}
END {
$pid_fd->remove if defined $pid_fd;
unlink($socket_file);
}
Script de démarrage init.d
root@muse:~# cat /etc/init.d/fcgi-perl
#! /bin/sh
### BEGIN INIT INFO
# Provides: fcgi-perl
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: fcgi-perl
# Description: start the fcgi-perl daemon
### END INIT INFO
# Author: Boris HUISGEN <bhuisgen@hbis.fr>
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC=fcgi-perl
NAME=fcgi-perl
DAEMON=/etc/nginx/$NAME.pl
PIDFILE=/var/run/fcgi-perl.pid
SOCKETFILE=/var/run/fcgi-perl.sock
[ -x "$DAEMON" ] || exit 0
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
. /lib/init/vars.sh
. /lib/lsb/init-functions
do_start()
{
[ -e $PIDFILE ] && return 1
echo "Starting $PROVIDES..."
$DAEMON &
[ ! -e $PIDFILE ] && sleep 1
[ ! -e $PIDFILE ] && return 2
return 0
}
do_stop()
{
[ ! -e $PIDFILE ] && return 1
echo "Stopping $PROVIDES..."
kill `cat $PIDFILE`
rm -f $PIDFILE
rm -f $SOCKETFILE
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
;;
restart)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;;
*) log_end_msg 1 ;;
esac
;;
*)
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 3
;;
esac
:
Configuration Nginx
server {
listen 80;
server_name localhost;
location / {
root /var/www/default;
index index.cgi index.html;
}
location ~ \.cgi$ {
fastcgi_pass unix:/var/run/fcgi-perl.sock;
fastcgi_index index.cgi;
fastcgi_param HTTP_ACCEPT_ENCODING gzip,deflate;
include fastcgi_params;
}
}