[[Vorlage(Getestet, bionic)]] {{{#!vorlage Wissen [:Pakete installieren: Installation von Programmen] [:Terminal: Ein Terminal verwenden] [:Editor: Einen Editor verwenden] [:mit Root-Rechten arbeiten:] [:Rechte: Rechte für Dateien und Ordner ändern] }}} [:Perl:] ist eine vielseitige Skriptsprache, die vor allem vor der starken Verbreitung von [:PHP:] häufig für die serverseitige Implementierung von Webapplikationen wurde und auch heute noch einen tauglichen Kandidaten für diesen Anwendungsfall darstellt. [:nginx:] ist ein mittlerweile sehr beliebter und schlanker Webserver, der die [wikipedia:FastCGI:]-Schnittstelle unterstützt und sich damit für die serverseitige Programmierung an jede Programmiersprache binden lässt, die diese Schnittstelle bedienen kann. Dieser Artikel beschreibt eine Möglichkeit, wie sich Perl und nginx miteinander kombinieren lassen. Dabei steht die Verwendung von Paketen aus den offiziellen Paketquellen im Vordergrund. Eine hier nicht näher beschriebene Alternative ist der Bezug der genannten Perl-Module von [http://www.cpan.org/ CPAN], was sich für diejenigen anbietet, die sich der möglichen Risiken und Wechselwirkungen beim Einsatz von Paketen und Programmen aus Fremdquellen bewusst sind und dennoch eine neuere/andere Version benötigen. {{{#!vorlage Warnung Mit der Anbindung von Perl über die FastCGI-Schnittstelle kann der gesamte Sprachumfang Perls einschließlich des Zugriffs auf Systemfunktionen genutzt werden. Dies sollte bei der Vergabe von Berechtigungen und der Auswahl der Dienstkonten berücksichtigt werden. }}} = Installation = Für den Aufbau der hier dargestellten Umgebung ist neben eine installierten [:nginx/#Installation:nginx Webserver] die Installation des folgenden Pakets notwendig[1]: {{{#!vorlage Paketinstallation libfcgi-perl }}} = Konfiguration = Die Konfiguration der zuvor installierten Pakete erfolgt in mehreren Schritten. Zuerst entsteht ein Wrapper um das soeben installierte FCGI-Modul, der dieses an einen Netzwerksocket bindet. Im nächsten Schritt erfolgt die Anpassung von nginx zur Nutzung dieses Netzwerksockets für Perl-Skripte. Zum Abschluss wird eine [:systemd/Service_Units:Service Unit] eingerichtet, um den Wrapper steuern zu können. == Perl FCGI-Wrapper== Der Perl FCGI-Wrapper sorgt dafür, dass das FCGI-Modul an einen Socket gebunden wird und dort dauerhaft auf Aufträge wartet. Grundsätzlich ist eine Bindung sowohl über einen Netzwerk-Socket (wie hier beschrieben) als auch einen [wikipedia:POSIX_local_inter-process_communication_socket:Unix Domain Socket] möglich. Das hier aufgeführte Skript bindet das FCGI-Modul an den Port 9000 der lokalen Loopback-Adresse (127.0.0.1). Die Website, von der dieses Skript abgeleitet ist, ist nicht mehr direkt verfügbar, daher an dieser Stelle ein [https://web.archive.org/web/20090227053237/http://wiki.codemongers.com/NginxSimpleCGI Link] {en} auf die [https://archive.org/web/web.php Wayback Machine] des [https://archive.org/ Internet Archive] {en}. {{{#!code perl #!/usr/bin/perl use FCGI; use Socket; use POSIX qw(setsid); require 'syscall.ph'; &daemonize; #this keeps the program alive or something after exec'ing perl scripts END() { } BEGIN() { } *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 { $socket = FCGI::OpenSocket( "127.0.0.1:9000", 10 ); #use IP sockets $request = FCGI::Request( \*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket ); if ($request) { request_loop()}; FCGI::CloseSocket( $socket ); } sub request_loop { while( $request->Accept() >= 0 ) { #processing any STDIN input from WebServer (for CGI-POST actions) $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; } } #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); 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 - "; print "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 = ) { print $s; } close KID_TO_READ; 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(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 "; print "exist or is not executable by this process.\n"; } } } }}} Gespeichert wird das Perl-Skript unter '''/usr/local/bin/perl-fastcgi''' - oder einem beliebigen anderen einprägsamen Namen[3][4]. Der neue Name muss in der später angelegten Service Unit ebenso angepasst werden. Mit dem Befehl {{{#!vorlage Befehl chmod 755 /usr/local/bin/perl-fastcgi }}} wird dafür Sorge getragen, dass alle das Skript ausführen dürfen, aber nur `root` Änderungen am Skript vornehmen darf[2][4][5]. Testweise sollte der Aufruf von {{{#!vorlage Befehl /usr/local/bin/perl-fastcgi }}} einen neuen Prozess erzeugen, der auf Port 9000 lauscht. Nach dem Start des Wrappers ist der erste Schritt zum Ziel abgeschlossen: Es können Perl-Skripte über die FastCGI-Schnittstelle an den wartenden Interpreter übergeben werden. == nginx == Nachdem mit dem FastCGI-Wrapper im letzten Abschnitt ein Prozess geschaffen wurde, der Perl-Skripte verarbeiten kann, wird nginx in diesem Abschnitt so konfiguriert, dass dieser Webserver die Skripte auch an den Prozess übergibt. nginx ist ein sehr vielseitig konfigurierbarer Webserver. Die unten stehende Konfiguration ist daher also als absolutes Minimum zu verstehen und sollte in jedem Fall an die konkreten Anforderungen angepasst werden. Da die Konfiguration der Standardseite geändert wird, ist die Originaldatei entsprechend zu sichern. Die zu ändernde Datei heißt '''/etc/nginx/sites-available/default''' und erhält den Inhalt[3][4]: {{{ server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm index.pl index.nginx-debian.html; server_name _; location / { try_files $uri $uri/ =404; } location ~ \.pl$ { include fastcgi.conf; fastcgi_pass 127.0.0.1:9000; } } }}} Nach dem Austausch des Inhalts dieser Datei wird der nginx-Dienst mit {{{#!vorlage befehl sudo systemctl restart nginx }}} neu gestartet[2]. Sollte der Perl-Prozess vom vorherigen Abschnitt noch laufen, könnten jetzt bereits pl-Dateien im Verzeichnis '''/var/www/html''' und dessen Unterverzeichnissen ausgeführt werden. Zum Testen kann eine kleine '''index.pl''' mit nachfolgendem Inhalt im zuvor genannten Verzeichnis und folgendem Inhalt erstellt werden[3][4]: {{{ #!/usr/bin/env perl print "Content-type: text/html\n\n"; print < Perl funktioniert!

Perl funktioniert!

HTML }}} Das Skript ist vor dem Test ausführbar zu machen[5]: {{{#!vorlage befehl sudo chmod +x /var/www/html/index.pl }}} Ein Aufruf des Rechners im Webbrowser sollte feststellen, dass Perl funktioniert. Falls nicht, ist nochmals zu prüfen, ob die Dateirechte und -namen passen. Nach diesem Test kann der Perl-Prozess selbst beendet werden. == Service Unit == Damit der Wrapper auch als Systemdienst verwaltet werden kann, fehlt nun noch die Anlage einer Service-Unit für systemd. Auch hier gibt es wieder mehrere Detaillierungsgrade der Konfiguration, wobei die abgebildete Unit-Definition einen rudimentären Dienst aufbauen hilft. Die Service-Unit wird hier der Einheitlichkeit halber '''perl-fastcgi.service''' genannt und im Verzeichnis '''/etc/systemd/system''' abgelegt[2][3]. Nach der Anlage ist wieder darauf zu achten, dass die Dateiberechtigungen den Dienst vor unberechtigten Änderungen schützen[5]. {{{ [Unit] Description=Daemonize Perl FastCGI wrapper After=network-online.target [Service] ExecStart=/usr/local/bin/perl-fastcgi Type=forking User=www-data [Install] WantedBy=multi-user.target }}} Mit den Befehlen {{{#!vorlage befehl sudo systemctl daemon-reload sudo systemctl start perl-fastcgi }}} wird die neu angelegte Service-Unit eingelesen und der Dienst gestartet[2]. Sollte etwas nicht funktionieren, sollte zuerst überprüft werden, ob der Wrapper wie in der Direktive `ExecStart` genannt wurde. = Links = * [:nginx:] - Hauptartikel hier im Wiki zu nginx * [:Perl:] - Hauptartikel hier im Wiki zu Perl #tag: Server, Perl