By Mohamad Wael

Posted :

How to setup nginx with cgi , fastcgi and c , bash , lisp , or any other programming language on debian and freebsd ?

What is CGI , fastCGI , fcgiwrap , FastCGI Development Kit , featured image

CGI stands for the common gateway interface . It is a way , for a web server to run external applications .

Each application or script or whatever , will have a process created and destroyed for each request . The web server is in charge of creating and destroying the processes , and is the owner of the process .

Messages are transferred from the web server , to the application , using environment variables . nginx does not actually support CGI .

FastCGI stands for the fast common gateway interface .

The basic concept to get , is that it is not the server who is responsible for creating , or owning the external application process . The external application is created once , is a long running process , is supposed to handle multiple requests , as for example in having a loop , which handles all the received requests .

Messages are also transferred using environment variables , through for example a pipe , or a unix socket , or TCP/IP .

This model of work allows caching , for example of database connections , and might help in the prevention of a denial of service , which might occur in the case of CGI .

To use fastCGI with nginx , two software libraries can be used , fcgiwrap or the FastCGI Development Kit .

fcgiwrap is simply a simple server , which acts as a wrapper for CGI using fastCGI . This enables nginx to run any script or application , as if by using the CGI specification , which is more correctly put , as having CGI wrapped using fastCGI .

Install nginx , and fcgiwrap , using :

root$ pkg install nginx-full fcgiwrap
# install nginx and fcgiwrap on FreeBSD .

root$ apt-get install nginx-full fcgiwrap
# install nginx and fcgiwrap on Debian .

Configure nginx , to add a location block , to the default server block , as in :

# For FreeBSD

root$ nano /usr/local/etc/nginx/nginx.conf
# ctrl-w to search for : server
# and add a location block under
# server as in  :

server {
    listen       80;
    server_name  localhost;
    ...

    # add this location block
    location /cgi/ {
        gzip off;
        root /home/difyel/; 
        fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      }
    ...


# For Debian 

root$ nano /etc/nginx/sites-enabled/default
# ctrl-w to search for server {
# Add under server the content 
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    ...

    # add this location block
    location /cgi/ {
        gzip off;
        root /home/difyel/; 
        fastcgi_pass unix:/var/run/fcgiwrap.socket;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      }
    ...



# Finally for Debian , and FreeBSD 

# Create a directory named cgi under
# the location you specified in the
# root directive , for example as
# a regular user , you can issue :
# mkdir -p /home/difyel/cgi/
# You can test the configuration for
# correctness using nginx -t
# for debian only , restart nginx 
# using service nginx restart

For freeBSD additionally , fcgiwrap and nginx must be configured as follows :

root$ nano /etc/rc.conf
# edit /etc/rc.conf , and add the following

nginx_enable="yes"
fcgiwrap_enable="yes"
fcgiwrap_socket_owner="www"
fcgiwrap_flags="-f -c 2"
# -c 2 means prefork 2 fcgiwrap
# processes , and -f means 
# redirect errors to web server 
# logs .

# ctrl-x to exit and save when prompted


root$ service nginx start
# start the nginx service

root$ service fcgiwrap start
# start the fcgiwrap service

Test the programming languages that you want , by placing your executables or scripts , in the cgi folder which was just created , and visiting the address localhost/cgi/your-program .

# example hello.lsp

# sbcl must be installed using
# debian  :  apt-get install sbcl
# freeBSD :  pkg install sbcl
# The script must be made executable
# as in chmod +x hello.lsp
# note that the first line for debian 
# must be #!/usr/bin/sbcl --script

#!/usr/local/bin/sbcl --script
(format t "Content-Type:text/html~%~%")
(format t "~a" (sb-unix::posix-getenv "HTTP_USER_AGENT"))


# example hello.bash

# For freeBSD bash must be 
# installed , or another shell 
# must be specified . 
# Bash can be installed under 
# freeBSD by using :
# pkg install bash
# The script must be made 
# executable , as in :
# chmod+x hello.bash  
# note that for debian , the 
# first line of the script , 
# must be #!/usr/bin/bash

#!/usr/local/bin/bash
printf 'Content-type: text/html\n\n'
echo $HTTP_USER_AGENT


# example hello.out

# For c , just write a hello.c
# program and compile it , for example
# using gcc -o hello.out hello.c

#include <stdio.h>
#include <stdlib.h>

int
        main
            (void ) {
    printf ("Content-type: text/html\n\n" );
    printf ("%s\n" , getenv("HTTP_USER_AGENT" ) );}

The list of environment variables that can be used , can be found under the wikipedia cgi article .

Concerning the fastCGI specification , it was created by the Open Market company , and the official website was fastcgi.com , which is not operational nowadays , but can be accessed using web archive , as in the provided link .

To install fastCGI , it can be done as follows :

root$ pkg install fcgi-devkit spawn-fcgi
# For FreeBSD

root$ apt-get install libfcgi-dev spawn-fcgi
# For debian

Add an nginx location , which will be handled by a fastCGI application .

# For FreeBSD

root$ nano /usr/local/etc/nginx/nginx.conf
# ctrl-w to search for : server
# and add a location block under
# server as in  :

server {
    listen       80;
    server_name  localhost;
    ...

    # add this location block
    location /fcgi/ {
        gzip off;
        fastcgi_pass 127.0.0.1:9100;
        include fastcgi_params;
      }
    ...


# For Debian 

root$ nano /etc/nginx/sites-enabled/default
# ctrl-w to search for server {
# Add under server the content 
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    ...

    # add this location block
    location /fcgi/ {
        gzip off;
        fastcgi_pass 127.0.0.1:9100;
        include fastcgi_params;
      }
    ...



# Finally for Debian , and FreeBSD 

# Test the configuration for any 
# error using nginx -t , and 
# restart the server using 
# service nginx restart 

Now , for example , to create a fastCGI application using C , It can be done as follows :


# example /home/difyel/hello.c

# Create a C source file , for 
# example hello.c 

#include "fcgi_stdio.h"
#include <stdio.h>
#include <stdlib.h>

int 
        main
            (void ){
  while (FCGI_Accept ( ) >= 0 ){
	printf ("Content-type: text/html;\n\n" );
    printf ("%s\n" , getenv("HTTP_USER_AGENT" ) );}}
    

# Compile the C source file using the command 
difyel$ gcc -lfcgi -o hello.out hello.c

# spawn a process using spawn-fcgi as in :
spawn-fcgi -a127.0.0.1 -p9100 ./hello.out

Now , if you visit any page under localhost/fcgi/ , the hello.out process will be in charge of returning a response , in this example program , it just returns the user agent .

Examples on fastcgi.com/devkit/doc/fcgi-tcl.htm , are provided on how to integrate the fastCGI library , with for example , the Tcl interpreter .