Site Tools


software:perl:fastcgi

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
software:perl:fastcgi [2015/05/20 18:25]
– ru:software:fastcgi_perl переименовано в ru:software:perl:fastcgi root
software:perl:fastcgi [2022/02/05 03:59]
root
Line 1: Line 1:
 +{{tag>software freebsd perl deprecated mysoft}}
 +
 ====== Perl fastcgi daemon ====== ====== Perl fastcgi daemon ======
-Поставил nginx вместо lighttpd и долго мучался с подключением perl. +Nginx, в отличии от lighttpd не умеет сам выполнять perl скриптыа готовых fcgi демонов для этого не было в 2009 годукогда я перешёл на nginx.\\
-Не нашёл ничего чтобы работало демоном для перла по fast-cgi. +
-Зато было две модификации перлового скриптакоторый как раз и работал по fast-cgi. +
-Пришлось самому его дописывать и делать обёртку стартового скрипта. +
-chroot не тестировал, но работать должнопотому что за основу брался рабочий скрипт от spawn-fcgi из соседней ветки: [url=http://www.netlab.linkpc.net/forum/index.php?topic=6.0]http://www.netlab.linkpc.net/forum/index.php?topic=6.0[/url]+
  
 +----
  
-Пример настроек в rc.conf+<note important>Сейчас, в 2018 я перешёл на [[https://github.com/gnosek/fcgiwrap|fcgiwrap]]. Настраивается предельно просто.</note>\\ 
-[code]perl_fcgi_enable="YES"+Так же хорошо работает uWSGI, инструкции по настройке: [[http://vladimir-stupin.blogspot.nl/2014/08/nginx-php5-fpm-uwsgi.html|Настройка nginx, php5-fpm и uwsgi]] и [[http://uwsgi-docs.readthedocs.io/en/latest/CGI.html|Running CGI scripts on uWSGI]]. Главное не забыть в конфиге nginx <code>uwsgi_modifier1 9;</code> 
 + 
 +---- 
 + 
 +Демон не моя разработка, я нашёл несколько готовых вариантов, доработал их немного, добавил rc.d скрипт для FreeBSD. В коде демона есть отсылки к оригиналам.\\ 
 +Работа chroot не проверялась, остальное вроде работает.\\ 
 +Часть не реализованных в демоне опций выполняется стартовым скриптом (chroot, смена пользователя и группы), часть не реализована (смена владельца и группы на сокете).\\ 
 + 
 +**Стартовый скрипт**: [[http://netlab.linkpc.net/download/software/perl/fastcgi/perl-fcgi|perl-fcgi]] (на FreeBSD расположить в /usr/local/etc/rc.d)\\ 
 +**Демон**[[http://netlab.linkpc.net/download/software/perl/fastcgi/perl-fcgi.pl|perl-fcgi.pl]] (на FreeBSD расположить в /usr/local/etc/ - можно поменять в стартовом скрипте, см выше)\\ 
 +**Лицензия**: BSD\\ 
 + 
 +**Более продвинутый вариант**: [[https://gitorious.org/perl-fpm/perl-fpm/|perl-fpm от NiTr0]]\\ 
 +**Обсуждение на форуме**: [[http://forum.nag.ru/forum/index.php?showtopic=83021|forum.nag.ru]] 
 + 
 + 
 + 
 +===== Пример настроек ===== 
 +В rc.conf для FreeBSD добавляем: 
 +<code>perl_fcgi_enable="YES"
 perl_fcgi_pidfile="/var/run/perl-fcgi.pid" perl_fcgi_pidfile="/var/run/perl-fcgi.pid"
 perl_fcgi_user="www" perl_fcgi_user="www"
Line 14: Line 32:
 perl_fcgi_chdir="/" perl_fcgi_chdir="/"
 perl_fcgi_chroot="" perl_fcgi_chroot=""
-perl_fcgi_socket="/tmp/perl-fcgi.sock"+perl_fcgi_socket="127.0.0.1:53676" 
 +perl_fcgi_socket="/var/run/perl-fcgi.sock"
 perl_fcgi_socketbacklog="100" perl_fcgi_socketbacklog="100"
-perl_fcgi_socketmode="0777"+perl_fcgi_socketmode="1777"
 perl_fcgi_children="2" perl_fcgi_children="2"
 perl_fcgi_childrentimeout="10" perl_fcgi_childrentimeout="10"
-perl_fcgi_max_requests="10000+perl_fcgi_max_requests="100
-perl_fcgi_path_env="/bin:/usr/bin"[/code+perl_fcgi_path_env="/bin:/usr/bin"</code> 
- +  * **enable** - разрешить запуск при загрузке 
- +  * **user** - имя пользователя под которым выполнять демона и скрипты 
-стартовый скрипт perl-fcgi (на FreeBSD ложить в /usr/local/etc/rc.d): +  * **group** группа под которыми выполнять демона и скрипты 
-[code]#!/bin/sh +  * **chdir** текущая директория для демона 
-### Rozhuk Ivan 2009.05 +  * **chroot** корневая директория для демона 
-### startup script file for perl-fcgi +  * **socket** unix сокет путь или ip:port для работы fcgi 
-### +  * **socketbacklog** размер очереди входящих соединений, только для сетевых сокетов 
- +  * **socketmode** - права доступа к сокету, только для unix сокета 
- +  * **children** количество дочерних процессов для выполнения скриптов 
-# PROVIDE: perl_fcgi +  * **childrentimeout** - максимальное время выполнения скрипта 
-# REQUIRE: DAEMON +  * **max_requests** - максимальное количество запросов обработанных одним дочерним процессом 
-# BEFORE:  LOGIN +  * **path_env** - перезаписать переменную окружения PATH
-# KEYWORD: shutdown +
- +
-. /etc/rc.subr +
- +
-name="perl_fcgi" +
-rcvar=`set_rcvar` +
- +
-load_rc_config $name +
- +
-: ${perl_fcgi_enable="NO"+
-: ${perl_fcgi_pidfile="/var/run/perl-fcgi.pid"} +
-: ${perl_fcgi_user="www"+
-: ${perl_fcgi_group="www"+
-: ${perl_fcgi_chdir=""+
-: ${perl_fcgi_chroot=""+
-: ${perl_fcgi_socket="127.0.0.1:9001"+
-: ${perl_fcgi_socketbacklog="10"+
-: ${perl_fcgi_socketmode="0777"+
-: ${perl_fcgi_children="5"+
-: ${perl_fcgi_childrentimeout="30"+
-: ${perl_fcgi_max_requests="1000"+
-: ${perl_fcgi_path_env="/bin:/usr/bin"+
- +
- +
-command="/usr/local/etc/perl-fcgi.pl" +
-command_args="-d ${perl_fcgi_chdir} -s ${perl_fcgi_socket} -sb ${perl_fcgi_socket} -M ${perl_fcgi_socketmode} -F ${perl_fcgi_children} -Ft ${perl_fcgi_childrentimeout} -Fm ${perl_fcgi_max_requests} -P ${perl_fcgi_pidfile} -e ${perl_fcgi_path_env}" +
-procname="perl-fcgi-pm" +
-pidfile="${perl_fcgi_chroot}${perl_fcgi_pidfile}" +
-required_dirs=${perl_fcgi_chroot} +
- +
-start_precmd="${name}_start_precmd" +
-stop_postcmd="${name}_stop_postcmd" +
- +
- +
-perl_fcgi_start_precmd() +
-+
- touch ${perl_fcgi_chroot}${pidfile} +
- chown ${perl_fcgi_user}:${perl_fcgi_group} ${perl_fcgi_chroot}${pidfile} +
-+
- +
-perl_fcgi_stop_postcmd() +
-+
- rm -f ${pidfile} +
-+
- +
-run_rc_command "$1" +
-[/code] +
- +
- +
-Демонический скрипт perl-fcgi.pl (ложить в /usr/local/etc/ - можно поменять в стартовом скрипте, см выше): +
-[code]#!/usr/bin/perl -w +
-### Rozhuk Ivan, 2009 +
-### fast cgi for perl scripts +
-### mod version 1.2 +
- +
-### origin: http://wiki.nginx.org//NginxSimpleCGI +
-### mod by  Denis S. Filimonov (Guest) on 13.03.2008 18:37 http://www.ruby-forum.com/attachment/1583/fastcgi-wrapper.pl +
-### mod by mark: http://www.linux.org.ru/view-message.jsp?msgid=3532327 +
-### final: http://wiki.nginx.org//NginxSimpleCGI +
-### additional: http://www.opennet.ru/base/dev/fastcgi_perl.txt.html +
- +
- +
-use strict; +
-use warnings; +
-use FCGI; # /usr/ports/www/p5-FastCGI +
-use FCGI::ProcManager qw(pm_manage pm_pre_dispatch pm_post_dispatch); # /usr/ports/www/p5-FCGI-ProcManager +
-use Socket; +
-use POSIX qw(setsid setuid); +
-use Getopt::Long; +
-require 'sys/syscall.ph'; +
- +
-# settings +
-my ($CURRENT_DIR,$SOCKET_ADDRESS,$SOCKET_BACKLOG,$SOCKET_MODE,$CHILDRENS_COUNT,$CHILDRENS_TIMEOUT,$CHILDRENS_MAX_REQ,$PIDFILE,$PATHENV); +
- +
-# global variables +
- +
- +
- +
-&startpoint(); +
- +
- +
-#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/; }; +
- +
- +
- +
-sub startpoint() +
-+
- if ($#ARGV!=-1) +
-+
- $CURRENT_DIR ='/'; +
- #$SOCKET_ADDRESS =''; +
- $SOCKET_BACKLOG =10; +
- $SOCKET_MODE =0777; +
- $CHILDRENS_COUNT =2; +
- $CHILDRENS_TIMEOUT =30; +
- $CHILDRENS_MAX_REQ =100; +
- #$PIDFILE =''; +
- #$PATHENV ='/bin:/usr/bin'; +
- +
- GetOptions( 'd:s' => \$CURRENT_DIR, +
- 's=s' => \$SOCKET_ADDRESS, +
- 'sb:i' => \$SOCKET_BACKLOG, +
- 'M:i' => \$SOCKET_MODE, +
- 'F:i' => \$CHILDRENS_COUNT, +
- 'Ft:i' => \$CHILDRENS_TIMEOUT, +
- 'Fm:i' => \$CHILDRENS_MAX_REQ, +
- 'P:s' => \$PIDFILE, +
- 'e:s' => \$PATHENV, +
- ); +
- +
- if (!defined($SOCKET_ADDRESS)) {usage();+
- +
- # untainte input +
- if ($SOCKET_ADDRESS =~ /^(.*)$/) {$SOCKET_ADDRESS = $1;} +
- if (defined($PIDFILE)) {if ($PIDFILE =~ /^(.*)$/) {$PIDFILE = $1;}} +
- if (defined($PATHENV)) +
-+
- if ($PIDFILE =~ /^(.*)$/) {$PIDFILE = $1;} +
- }else{ +
- $PATHENV='/bin:/usr/bin'; +
-+
- +
- +
- #print "SOCKET_ADDRESS: $SOCKET_ADDRESS SOCKET_BACKLOG: $SOCKET_BACKLOG CHILDRENS_COUNT: $CHILDRENS_COUNT CHILDRENS_TIMEOUT: $CHILDRENS_TIMEOUT PIDFILE: $PIDFILE\n"; +
- daemonize(); +
- }else{ +
- usage(); +
-+
-+
- +
- +
-sub usage +
-+
- print "Usage: perl-fcgi [options]\n\n"; +
- print " -d <directory> chdir to directory before spawning (default /)\n"; +
- print " -s <address/path> unix socket or tcp address:port\n"; +
- print " -sb <size> socket backlog size (default 10)\n"; +
- print " -M <mode> change Unix domain socket mode (default 0777)\n"; +
- print " -F <children> number of children to fork (default 2)\n"; +
- print " -Ft <timeout> children process timeout (default 30)\n"; +
- print " -Fm <num> children process max requests (default 100)\n"; +
- print " -P <path> name of PID-file for spawned process\n"; +
- print " -e <path> set new PATH environment (default /bin:/usr/bin)\n"; +
- #print "(root only)\n"; +
- #print " -c <directory> chroot to directory (default /)\n"; +
- #print " -S create socket before chroot() (default is to create the socket in the chroot)\n"; +
- #print " -u <user> change to user-id\n"; +
- #print " -g <group> change to group-id (default: primary group of user if -u is given)\n"; +
- #print " -U <user> change Unix domain socket owner to user-id\n"; +
- #print " -G <group> change Unix domain socket group to group-id\n"; +
- +
- exit; +
-+
- +
- +
-sub daemonize() +
-+
- delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer +
- $ENV{'PATH'} = $PATHENV; # set new path environment +
- chdir $CURRENT_DIR or die "Can't chdir to $CURRENT_DIR: $!\n"; +
- #setuid(65534) or die "Can't set uid: $!\n"; # nobody +
- +
- open(STDIN,  "+>/dev/null") or die "Can't open STDIN: $!\n"; +
- open(STDOUT, "+>&STDIN") or die "Can't open STDOUT: $!\n"; +
- open(STDERR, "+>&STDIN") or die "Can't open STDERR: $!\n"; +
- defined(my $tm = fork) or die "Can't fork: $!\n"; +
- exit if $tm; +
- setsid or die "Can't start a new session: $!\n"; +
- umask 0; +
- +
- main(); +
-+
- +
- +
-sub main +
-+
- my ($ListenSocket); +
- my ($proc_manager,$request,%req_params); +
- +
- $ListenSocket = FCGI::OpenSocket( $SOCKET_ADDRESS, $SOCKET_BACKLOG ); +
- if (defined($ListenSocket)) +
-+
- if (defined($PIDFILE)) +
-+
- open FILE, "> $PIDFILE" or die $!; +
- print FILE "$$\n"; +
- close FILE; +
-+
- +
- if (substr($SOCKET_ADDRESS,0,1) eq '/')  +
-+
- print "chmod($SOCKET_MODE,$SOCKET_ADDRESS)\n"; +
- chmod(oct($SOCKET_MODE),$SOCKET_ADDRESS); +
-+
- +
- $proc_manager = FCGI::ProcManager->new({ n_processes => $CHILDRENS_COUNT, die_timeout => $CHILDRENS_TIMEOUT }); +
- $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $ListenSocket, &FCGI::FAIL_ACCEPT_ON_INTR ); +
- $proc_manager->pm_manage(); +
- +
- if ($request) { request_loop(\$proc_manager,\$request,\%req_params) }; +
- +
- FCGI::CloseSocket( $ListenSocket ); +
- if (substr($SOCKET_ADDRESS,0,1) eq '/') {unlink($SOCKET_ADDRESS);+
- if (defined($PIDFILE)) {unlink($PIDFILE);+
-+
-+
- +
- +
-sub request_loop() +
-+
- my ($proc_manager_ref)=$_[0]; +
- my ($request_ref)=$_[1]; +
- my ($req_params_ref)=$_[2]; +
- my ($stdin_passthrough,$req_len,$key,$pid_child,$req_count); +
- +
- $req_count=1; +
- while( $$request_ref->Accept() >= 0 ) +
-+
- $$proc_manager_ref->pm_pre_dispatch(); +
-  +
- #processing any STDIN input from WebServer (for CGI-POST actions) +
- $stdin_passthrough =''; +
- { no warnings; $req_len = 0 + $$req_params_ref{'CONTENT_LENGTH'}; }; +
- if (($$req_params_ref{'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_ref{SCRIPT_FILENAME}) &&  #can I execute this? +
- (-s $$req_params_ref{SCRIPT_FILENAME}) &&  #Is this file empty? +
- (-r $$req_params_ref{SCRIPT_FILENAME})     #can I read this file? +
- ){ +
- +
- pipe(CHILD_RD, PARENT_WR); +
- $pid_child = open(KID_TO_READ, "-|"); +
- unless(defined($pid_child)) +
-+
- print("Content-type: text/plain\r\n\r\n"); +
-                     print "Error: CGI app returned no output - Executing $$req_params_ref{SCRIPT_FILENAME} failed !\n"; +
- next; +
-+
- +
- if ($pid_child > 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_child, 0); +
- }else{ +
- foreach $key ( keys %{$req_params_ref}){ $ENV{$key} = $$req_params_ref{$key};+
- # cd to the script's local directory +
- if ($$req_params_ref{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_ref{SCRIPT_FILENAME}); +
- die("exec failed"); +
-+
- }else{ +
- print("Content-type: text/plain\r\n\r\n"); +
- print "Error: No such CGI app - $$req_params_ref{SCRIPT_FILENAME} may not exist or is not executable by this process.\n"; +
-+
- +
- $req_count++; +
- exit if $req_count > $CHILDRENS_MAX_REQ;+
  
- $$proc_manager_ref->pm_post_dispatch(); 
- } 
-} 
-[/code] 
  
 +===== Параметры командной строки демона =====
 +  * **-d** <directory> - chdir to directory before spawning (default /)
 +  * **-s** <address/path> - unix socket or tcp address:port
 +  * **-sb** <size> - socket backlog size (default 10)
 +  * **-M** <mode> - change Unix domain socket mode (default 0777)
 +  * **-F** <children> - number of children to fork (default 2)
 +  * **-Ft** <timeout> - children process timeout (default 30)
 +  * **-Fm** <num> - children process max requests (default 100)
 +  * **-P** <path> - name of PID-file for spawned process
 +  * **-e** <path> - set new PATH environment (default /bin:/usr/bin)
  
-Постарался проследить историю развития скрипта, может что то и напутал. 
-Версию с более продвинутой логикой внутри мне не удалось заставить работать, поэтому я взял версию немного по проще, судя по описанию она не возвращает сообщений об ошибках в скриптах. 
  
-В коде видно часть не реализованных опций - часть из них реализуется стартовым скриптом (chroot, смена пользователя и группы), часть нет (смена владельца и группы на сокете). 
software/perl/fastcgi.txt · Last modified: 2022/02/05 04:02 by root