Apache cgi scripts on Linux Mint 18.1

7 June 2017 Author: Erik Lievaart Cgi scripts can be used to generate or modify a response to requests on the Apache webserver. Roughly any shell or programming language can be used. Cgi offers hassle free means for generating dynamic output. Creating them is by no means a complicated task, but I found that many of the help pages skip some of the steps required to get up and running. Having struggled through this today, I am in the perfect position to create a complete step by step guide to get there. This guide is purely focused at getting your cgi scripts running and will ignore topics such as security and performance. I will show you how to execute a cgi script for a specific url, In my next article I will show you how to run scripts for a range of urls.

Lets get started:

Running a specific cgi script when requesting a url

I am going to asume a clean installation of Linux Mint 18.1 and list all the steps that need to be taken to get your hello world script up and running. If you are running a different version of linux, file paths and modifications may change.

This guide identifies the following steps

Installing Apache

Apache does not ship with linux mint by default, to install it:
sudo apt-get update
sudo apt-get install apache2
Apache is now installed and running as a service. Opening firefox at http://127.0.0.1:80should show the default welcome page. If your version of linux mint is different, read the file carefully, because it contains some of the configuration locations that may have changed.
sudo service apache2
will show you some commands available for starting, stopping, reloading apache etc.

enabling mod_cgid

In this section we will enable mod_cgid. https://httpd.apache.org/docs/2.4/howto/cgi.html You can enable cgi using the a2enmod script:
sudo a2enmod cgi
Next force reload to apply the changes:
sudo service apache2 force-reload
To verify that the module is currently active:
apache2ctl -M
The list should contain "cgid_module" (the rest of this paragraph is optional).

Disabling cgi would be done using

sudo a2dismod cgi

Some background on how the a2enmod script works. Apache ships with a whole bunch of modules, but not all of them are on by default. The complete list of modules can be found in the following directory:

ls /etc/apache2/mods-available
The list of modules that is enabled can be found in:
ls -l /etc/apache2/mods-enabled
a2enmod enables mods by creating soft links in the mods-enabled directory To enable(disable) any of these modules manually, simply create(delete) a soft link in the directory mentioned above.
sudo ln -s  /etc/apache2/mods-available/cgid.* /etc/apache2/mods-enabled

configuring cgi

So now mod_cgid is active, but it is not configured yet to run cgi scripts. On linux mint apache configures a virtual host (website) for port 80 in the following file by default:
sudo vi /etc/apache2/sites-enabled/000-default.conf
Add the following right before the </VirtualHost> closing tag:
ScriptAlias /cgi-bin/ /var/www/cgi-bin/

	<Directory "/var/www/cgi/bin">
		AllowOverride None
		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
		Order allow,deny
		Allow from all
	</Directory>
Now apache knows that any url starting with /cgi-bin/ should find a file in /var/www/cgi-bin/ and execute it. The (system) output of the script will be sent to the browser. To apply the changes:
sudo service apache2 restart
Now before we can test our configuration, the last step is to create a cgi script.

creating a cgi script

I will give you the full script first and explain the contents afterwards. That will complete the tutorial. Finally, the end of this document will show some variations of scripts.

To create the cgi script, first we ensure that the cgi-bin dir exists:

sudo mkdir -p /var/www/cgi-bin/
Then we create a new script:
sudo vi /var/www/cgi-bin/hello.cgi
Add the following contents to the file:
#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<html>"
echo "<body>"
date
echo "<h1>My first cgi script</h1>"
echo "script run dir $(pwd)"
echo "<h2>Environment variables</h2>"
echo "<pre>"
env
echo "</pre>"
echo "</body>"
echo "</html>"
Lastly, we make sure the script is executable.
sudo chmod a+x /var/www/cgi-bin/*
You can always check if a script compiles and runs by running it directly:
/var/www/cgi-bin/hello.cgi
It is time to open the following url to check if we have succeeded:
http://127.0.0.1/cgi-bin/hello.cgi

Now we will examine the script in a little more detail for those who want some extra background.

#!/bin/sh
This first line is an instruction to linux, to tell it which excutable (shell or programming language) to use to run the file. Here, the script is run in the bourne shell. For more info: https://en.wikipedia.org/wiki/Shebang_%28Unix%29
#!/bin/bash
Would run the script in the bourne again shell instead (it will still work).
echo "Content-type: text/html"
Set the Content type / MIME type of the response (https://en.wikipedia.org/wiki/MIME). Next the script prints some raw HTML and some extra info, which might be useful for your scripts. $(pwd) will print the directory the script is run in (/var/www/cgi-bin/). I also printed the environment variables, so you can see that the script has access to the query string. For example, if you open http://127.0.0.1/cgi-bin/hello.cgi?param=value, then you will see that the REQUEST_URI and QUERY_STRING environment variables now contain param=value. Please note that these are in encoded format and that using input parameters opens a whole new can of security worms.

A python example

As I have said at the beginning of this document, cgi scripts are not limited to shell scripts. Let's create a hello world script in python to illustrate this point:
sudo touch /var/www/cgi-bin/other.py
sudo chmod +x /var/www/cgi-bin/*
sudo vi /var/www/cgi-bin/other.py
Contents of the file:
#!/usr/bin/python3
print("Content-type: text/html")
print("")
print("Python says hello!")
Now view the result at: http://127.0.0.1/cgi-bin/other.py

A simple monitoring script

Here I will create a simple cgi script for monitoring the server's load as an illustration of how easy cgi makes it to create useful pages. Create a new script with execution rights:
sudo touch /var/www/cgi-bin/monitoring.cgi
sudo chmod +x /var/www/cgi-bin/*
sudo vi /var/www/cgi-bin/monitoring.cgi
Here is the sample script for a rudimentary monitoring page:
#!/bin/sh
echo "Content-type: text/html"
echo ""
echo "<html>"
echo "	<head>"
echo "		<meta http-equiv="refresh" content="5;">"
echo "	</head>"
echo "<body>"
echo "<h1>cpu usage</h1><pre>$(top -b -n2 | grep "Cpu(s)" | tail -n 1)</pre>"
echo "<h1>memory usage</h1><pre>$(free -h)</pre>"
echo "<h1>disk usage</h1><pre>$(df -h)</pre>"
echo "</body>"
Unfortunately top doesn't show the correct cpu usage on the first iteration. I had to apply a workaround that causes the script to wait on top for a second. So the page might be a little slow.

Check the result at: http://127.0.0.1/cgi-bin/monitoring.cgi Next: cgi handlers Main Page