This tutorial is strictly related to former one on LEMP Installation on Gentoo and treats other server extended issues such as enabling dynamic scripting languages like Perl or Bash or Ruby through Fcgiwrap Gateway, and edit Nginx Virtual Hosts configuration files to serve dynamic content using .pl, .rb and .cgi scripts.
Requirements
- LEMP stack installed on Gentoo – https://www.tecmint.com/install-lemp-in-gentoo-linux/
Step 1: Enable FCGIWRAP on Gentoo LEMP
Fcgiwrap is a part of Nginx FastCGI Common Gateway Interface which process other dynamic scripting languages, like Perl or Bash or Ruby scripts, works by processing requests received from Nginx, through TCP or Unix Sockets, in an independently manner and returns the produced result back to Nginx, which, in term, will forward responses back to end clients.
1. Let’s first start by installing FCcgiwrap process on Gentoo Linux using the following command.
# emerge --ask www-misc/fcgiwrap
2. By default Fcgiwrap package doesn’t provide any init scripts on Gentoo to manage the process. After the packages has been compiled and installed create the following init scripts that helps you to manage Fcgiwrap process using three approach: either launching the process using Unix Domain Sockets or using local TCP Sockets or using both at the same time.
Using TCP Socket Script
Create an init file on /etc/init.d/ path with the following file content.
# nano /etc/init.d/fcgiwrap
Add the following file content.
#!/sbin/runscript ip="0.0.0.0" port="12345" start() { ebegin "Starting fcgiwrap process..." /usr/sbin/fcgiwrap -s tcp:$ip:$port & tcp_sock=`netstat -tulpn | grep fcgiwrap` echo "Socket details: $tcp_sock" eend $? "Errors were encountered while starting fcgiwrap process" } stop() { ebegin "Stopping fcgiwrap process..." pid=`ps a | grep fcgiwrap | grep tcp | cut -d" " -f1` kill -s 1 $pid tcp_sock=`netstat -tulpn | grep fcgiwrap` if test $tcp_sock = 2> /dev/null ; then echo "Fcgiwrap process successfully stoped" tcp_sock=`netstat -atulpn | grep $port` if test $tcp_sock = 2> /dev/null ; then echo "No open fcgiwrap connection found..." else echo "Wait to close fcgiwrap open connections...please verify with 'status'" echo -e "Socket details: \n$tcp_sock" fi else echo "Fcgiwarp process is still running!" echo "Socket details: $tcp_sock" fi eend $? "Errors were encountered while stopping fcgiwrap process..." } status() { ebegin "Status fcgiwrap process..." tcp_sock=`netstat -atulpn | grep $port` if test $tcp_sock = 2> /dev/null ; then echo "Fcgiwrap process not running" else echo "Fcgiwarp process is running!" echo -e "Socket details: \n$tcp_sock" fi eend $? "Errors were encountered while stopping fcgiwrap process..." }
As you can see the script file holds two variable at the beginning, respectively ip and port. Change this variables with your own needs and make sure they don’t overlap with other services on your system, especially port variable – default here is 12345 – change accordingly.
Using 0.0.0.0 on IP variable enables the process to bind and listen on any IP (outside accessible if you don’t have a firewall ), but for security reasons you should change it to listen locally only, on 127.0.0.1, unless you have other reasons like remotely setup Fcgiwrap gateway on a different node for performance or load balancing.
3. After the file is created, append execution permissions and manage the daemon process using start, stop or status switches. The status switch will show you relevant socket information such as IP-PORT pair it listens and if any active connection where initialized. Also, if the process has active connections in TIME_WAIT state you cannot restart it until all TCP connections close.
# chmod +x /etc/init.d/fcgiwrap # service start fcgiwrap # /etc/init.d/fcgiwrap status
Using Unix Socket Script
As presented earlier Fcgiwrap can run simultaneously using both sockets, so will slightly change the name of the second script to fcgiwrap-unix-socket, to ensure that both can be started and run the same time.
# nano /etc/init.d/fcgiwrap-unix-socket
Use the following file content for UNIX socket.
#!/sbin/runscript sock_detail=`ps a | grep fcgiwrap-unix | head -1` start() { ebegin "Starting fcgiwrap-unix-socket process..." /usr/sbin/fcgiwrap -s unix:/run/fcgiwrap-unix.sock & sleep 2 /bin/chown nginx:nginx /run/fcgiwrap-unix.sock sleep 1 sock=`ls -al /run/fcgiwrap-unix.sock` echo "Socket details: $sock" eend $? "Errors were encountered while starting fcgiwrap process" } stop() { ebegin "Stopping fcgiwrap-unix-socket process..." pid=`ps a | grep fcgiwrap | grep unix | cut -d" " -f1` rm -f /run/fcgiwrap-unix.sock kill -s 1 $pid echo "Fcgiwrap process successfully stoped" #killall /usr/sbin/fcgiwrap sleep 1 echo "Socket details: $sock" eend $? "Errors were encountered while stopping fcgiwrap process..." } status() { ebegin "Status fcgiwrap-unix-socket process..." if test -S /run/fcgiwrap-unix.sock; then echo "Process is started with socket: $sock_detail" else echo "Fcgiwrap process not running!" fi eend $? "Errors were encountered while stopping fcgiwrap process..." }
4. Again assure that this file is executable and use the same service switches: start, stop or status. I have set the default path for this socket on /run/fcgiwrap-unix.sock system path. Start the process and verify it using status switch or list /run directory content and locate the socket, or use ps -a | grep fcgiwrap command.
# chmod +x /etc/init.d/fcgiwrap-unix-socket # service start fcgiwrap-unix-socket # /etc/init.d/fcgiwrap-unix-socket status # ps -a | grep fcgiwrap
As previously mentioned Fcgiwrap can run with both TCP and UNIX sockets simultaneous, but if you don’t need external gateway connections stick to Unix Domain Socket only, because it uses interprocess communication, which is faster than communication over TCP loopback connections, and uses less TCP overhead.
Step 2: Enable CGI Scripts on Nginx
5. For Nginx to parse and run Perl or Bash scripts through Fast Common Gateway Interface, Virtual Hosts must be configured with Fcgiwrap definitions on root path or location statements.
An example, is presented below (localhost), which activates Perl and CGI scripts on all files placed in root path (/var/www/localhost/htdocs/) with .pl and .cgi extension using Fcgiwrap TCP Sockets for default root document path, the second location using Unix Domain Sockets, with an index.pl file and the third location is using TCP sockets with an index.cgi file.
Place the following content, or just some parts of it, to your desired Virtual Host configuration file you want to activate dynamic Perl or Bash scripts with UNIX or TCP Sockets under different locations, by modifying fastcgi_pass argument statement.
# nano /etc/nginx/sites-available/localhost.conf
Edit localhost.conf to look like in the template below.
server { listen 80; server_name localhost; access_log /var/log/nginx/localhost_access_log main; error_log /var/log/nginx/localhost_error_log info; root /var/www/localhost/htdocs/; location / { autoindex on; index index.html index.htm index.php; } ## PHP –FPM Gateway ### location ~ \.php$ { try_files $uri =404; include /etc/nginx/fastcgi.conf; fastcgi_pass 127.0.0.1:9001; } ## Fcgiwrap Gateway on all files under root with TCP Sockets### location ~ \.(pl|cgi|rb)$ { fastcgi_index index.cgi index.pl; include /etc/nginx/fastcgi.conf; fastcgi_pass 127.0.0.1:12345; } ## Fcgiwrap Gateway on all files under root second folder with index.pl using UNIX Sockets### location /second { index index.pl; root /var/www/localhost/htdocs/; location ~ \.(pl|cgi|rb)$ { include /etc/nginx/fastcgi.conf; fastcgi_pass unix:/run/fcgiwrap-unix.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } ## Fcgiwrap Gateway on all files under root third folder with index.cgi using TCP Sockets### location /third { index index.cgi; location ~ \.(pl|cgi|rb)$ { include /etc/nginx/fastcgi.conf; fastcgi_pass 127.0.0.1:12345; } }
6. After you finish editing Nginx localhost.conf, or your specific Virtual Host configuration file, move to your website default document root path, create those two folders to reflect your location statement, and create index files for every location with its specific extension.
# cd /var/www/localhost/htdocs # mkdir second third
Create index.pl file on second location with the following content.
# nano /var/www/localhost/htdocs/second/index.pl
Add this content to get environment variables.
#!/usr/bin/perl print "Content-type: text/html\n\n"; print <<HTML; <html> <head><title>Perl Index</title></head> <body> <div align=center><h1>A Perl CGI index on second location with env variables</h1></div> </body> HTML print "Content-type: text/html\n\n"; foreach my $keys (sort keys %ENV) { print "$keys = $ENV{$keys}<br/>\n"; } exit;
Then create index.cgi file on third location with the following content.
# nano /var/www/localhost/htdocs/third/index.cgi
Add this content to get environment variables.
#!/bin/bash echo Content-type: text/html echo "" cat << EOF <HTML> <HEAD><TITLE>Bash script</TITLE></HEAD> <BODY><PRE> <div align=center><h1>A BASH CGI index on third location with env variables</h1></div> EOF env cat << EOF </BODY> </HTML> EOF
7. When finish editing, make both files executable, restart Nginx server and make sure that both Fcgiwrap sockets are running.
# chmod +x /var/www/localhost/htdocs/second/index.pl # chmod +x /var/www/localhost/htdocs/third/index.cgi # service nginx restart # service fcgiwrap start # service fcgiwrap-unix-socket start
Next, redirect your local browser on following URL.
http://localhost http://localhost/second/ http://localhost/third/
The result should appear as on below screenshots.
8. If everything is in place and correctly configured, enable both Fcgiwrap daemons to automatically start, after reboot by issuing the following commands (in case you have configured Nginx to use both CGI sockets).
# rc-update add fcgiwrap default # rc-update add fcgiwrap-unix-socket default
Step 3: Activate Ruby support on Fcgiwrap
9. If you need to run dynamic Ruby scripts on Nginx FCGI you must install Ruby interpreter on Gentoo with the following command.
# emerge --ask ruby
10. After the package has been compiled and installed, move to Nginx sites-available and edit localhost.conf file by appending the following statements before last curly bracket “ } ”, which activates support to run Ruby scripts on a fourth location under default document root path served by Nginx localhost.
# nano /etc/nginx/sites-available/localhost.conf
Use the following Nginx directives.
## Fcgiwrap Gateway on all files under root fourth folder with index.rb under TCP Sockets### location /fourth { index index.rb; location ~ \.rb$ { include /etc/nginx/fastcgi.conf; fastcgi_pass 127.0.0.1:12345; } } ## Last curly bracket which closes Nginx server definitions ## }
11. Now, to test configuration create the fourth directory under /var/www/localhost/htdocs path, create an executable Ruby index script with .rb extension and add the following content.
# mkdir /var/www/localhost/htdocs/fourth # nano /var/www/localhost/htdocs/fourth/index.rb
Ruby index.rb example.
#!/usr/bin/ruby puts "HTTP/1.0 200 OK" puts "Content-type: text/html\n\n" puts "<html><HEAD><TITLE>Ruby script</TITLE></HEAD>" puts "<BODY><PRE>" puts "<div align=center><h1>A Ruby CGI index on fourth location with env variables</h1></div>" system('env')
12. After you add execution permissions on file, restart Nginx daemon to apply configurations.
# chmod +x /var/www/localhost/htdocs/fourth/index.rb # service nginx restart
Open your browser and navigate to the URL http://localhost/fourth/, which should present you the following content.
That’s it for now, you have configured Nginx to serve dynamic Perl, Ruby and Bash scripts on FastCGI Gateway, but, be aware that running this kind of interpreted scripts on Nginx CGI Gateway can be dangerous and impose seriously security risks on you server because they run using active shells under you system, but can expand static barrier imposed by static HTML, adding dynamic functionality to your website.