CGI, the Common Gateway Interface is a simple way to write web applications. Especially when you are running Apache as the web server. Recently I wanted to show a few examples using CGI in various programming languages, but first I had to make sure CGI is enabled on my server.

I have been using the an Ubuntu based Vagrant image for my experiments but I think the same steps will work in any other Ubuntu-based or any Debian based system.

Install Apache 2

If you don't have it installed yet, you will need to install the web servers itself:

$ sudo apt-get install apache2

Install curl

curl can be used to fetch web pages. It is not a requirement for our set up, but it is nice to have on the server as it can be used to check the pages without opening a real browser. Besides, at least in my set up, I have configured the web server on a Virtual Environment, but I have not set up port-forwarding for port 80 yet and thus I would not be able to access the web server from my desktop. (The article about Vagrant development environment has explanation how to set up the port forwarding.)

$ sudo apt-get install curl

Try the web server

At this point we can try if the web server works:

$ curl http://127.0.0.1/

It will print some HTML on the screen.

Configure CGI

I looked around the /etc/apache2 directory, which is the standard place to find the configuration files of Apache. I've found the /etc/apache2/conf-available/serve-cgi-bin.conf file that has a symbolic link from /etc/apache2/conf-enabled/serve-cgi-bin.conf. It has a section that maps the /cgi-bin path in the URLs to the /usr/lib/cgi-bin/ directory in the hard disk and enables CGI execution in this directory.

examples/apache/serve-cgi-bin.conf

<IfModule mod_alias.c>
	<IfModule mod_cgi.c>
		Define ENABLE_USR_LIB_CGI_BIN
	</IfModule>

	<IfModule mod_cgid.c>
		Define ENABLE_USR_LIB_CGI_BIN
	</IfModule>

	<IfDefine ENABLE_USR_LIB_CGI_BIN>
		ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
		<Directory "/usr/lib/cgi-bin">
			AllowOverride None
			Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
			Require all granted
		</Directory>
	</IfDefine>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

That's not enough though. We also need to enable the CGI module of Apache.

The installed modules of Apache can be found in the /etc/apache2/mods-available directory. The cgi module is called cgi.load

The enabled modules have symbolic links in /etc/apache2/mods-enabled, but as I found out, the CGI module did not have a symbolic link there: The CGI module was not enabled by default.

$ cd /etc/apache2/mods-enabled
$ sudo ln -s ../mods-available/cgi.load

Added the symbolic link.

Reload Apache configuration

As the configuration of Apache has changed we need to tell Apache to reload its configuration files:

$ sudo service apache2 reload

Create the first CGI script

Now that we have enable CGI we can create our first CGI script.

This first CGI example will be created in Bash. Later on you can check out the solutions to the various web exercises Especially the Hello World! exercise and the Web Echo exercise and their solutions.

I've created a file called /usr/lib/cgi-bin/hw.sh using sudo vim /usr/lib/cgi-bin/hw.sh

examples/apache/hw.sh

#!/bin/bash
printf "Content-type: text/html\n\n"
printf "Hello World!\n"

Made it executable:

$ sudo chmod +x /usr/lib/cgi-bin/hw.sh

Then I could access it through Apache using:

$ curl http://127.0.0.1/cgi-bin/hw.sh
Hello World!

Troubleshooting

If the curl request returns 404 Not Found then either the file is not in the correct place, or the URL given to curl is incorrect.

If the curl requests return 500 Internal Server Error you might have forgotten to make the script executable using sudo chmod +x /usr/lib/cgi-bin/hw.sh

or the hashbang line (The first line that should look like this #!/bin/bash was not typed in correctly.

Another common source of error is the difference between the newlines in MS Windows and Linux in text files. You have to make sure that your script has the Unix/Linux line-ending. One of the best ways might be to run dos2unix hw.sh that will replace the Windows-newlines by Unix-newlines.

Lastly, the 500 error might occur if the first line printed by the script is not Content-type: text/html followed by 2(!) newlines.

Further reading

Check out all the articles related to CGI and Perl and CGI and Ruby.