Installing FcgiWrap and Enabling Perl, Ruby and Bash Dynamic Languages on Gentoo LEMP

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.

Install FcgiWrap with Perl, Ruby and Bash
Install FcgiWrap with Perl, Ruby and Bash

Requirements

  1. 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
Install FCcgiwrap in Gentoo Linux
Install FCcgiwrap Package

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..."
}
Using TCP Socket Script
Using TCP Socket Script

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
Start FcgiWrap Service
Start FcgiWrap Service
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..."
}
Using Unix Socket Script
Using Unix Socket Script

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
Start and Verify Fcgiwrap
Start and Verify 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.

Unix Domain Socket
Unix Domain Socket

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.

Verify CGI Directory
Verify CGI Directory
A Perl CGI Index Page
A Perl CGI Index Page
A Bash CGI Index Page
A Bash CGI Index Page

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
Install Ruby Interpreter
Install Ruby Interpreter

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 ##
}
Enable Ruby Support on Fcgiwrap
Enable Ruby Support on Fcgiwrap

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.

Ruby CGI Index Page
Ruby CGI Index Page

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.

Matei Cezar
I'am a computer addicted guy, a fan of open source and linux based system software, have about 4 years experience with Linux distributions desktop, servers and bash scripting.

Each tutorial at TecMint is created by a team of experienced Linux system administrators so that it meets our high-quality standards.

Join the TecMint Weekly Newsletter (More Than 156,129 Linux Enthusiasts Have Subscribed)
Was this article helpful? Please add a comment or buy me a coffee to show your appreciation.

Got something to say? Join the discussion.

Thank you for taking the time to share your thoughts with us. We appreciate your decision to leave a comment and value your contribution to the discussion. It's important to note that we moderate all comments in accordance with our comment policy to ensure a respectful and constructive conversation.

Rest assured that your email address will remain private and will not be published or shared with anyone. We prioritize the privacy and security of our users.