The Apache HTTP Web Server is a powerful and extensible web server that is the “A” in “LAMP”. One of the neat things about Apache is its API for writing custom modules.

Nick Kew wrote an excellent book called The Apache Modules Book. Anyone who is serious about Apache module development must buy this book.

Modules can be written a number of ways, but the most common way is to use the C programming language. For an C/C++ development IDE, I use KDevelop. It is pretty easy to use once you figure out what you need to do.

It is possible to write modules in C++, but I don’t recommend it if your module’s source can’t be contained in a single source file. There’s all sorts of interesting issues with exported symbols and static function declarations. Another reason to stick with C is pretty much all core modules and examples are written using C. You may give it a try and determine that it works just fine for your project.

Prerequisites

Before you begin, there is a handful of applications and libraries you must have installed:

  • Apache 2
  • KDevelop 3.4
  • GCC (bundled with “build-essential” package)
  • automake
  • autoconf

Creating the Project

Launch KDevelop and select “New Project” from the Project menu. Since we are focusing on using C, select “Simple Hello world program” under the “C” folder. Give your module an “Application name” and specify the location to create the project.

KDevelop New Project

On the next page of the wizard, you must enter your name, but your email address is not required.

KDevelop New Project

The next couple wizard screens ask about version control and source templates. After finishing the wizard, you will be back at the IDE with the new project created.

KDevelop IDE

The Code

Delete all of the source code that the editor created. Next paste the following code which originated from Nick’s version on The Apache Modules Book Companion site.

#include <httpd.h>
#include <http_protocol.h>
#include <http_config.h>

static int helloworld_handler(request_rec* r)
{
	if (!r->handler || strcmp(r->handler, "helloworld"))
		return DECLINED;
	
	if (r->method_number != M_GET)
		return HTTP_METHOD_NOT_ALLOWED;
	
	ap_set_content_type(r, "text/html;charset=ascii");
	ap_rputs("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">n", r);
	ap_rputs("<html><head><title>Hello World!</title></head>;", r);
	ap_rputs("<body><h1>Hello World!</h1></body></html>", r);
	return OK;
}

static void register_hooks(apr_pool_t* pool)
{
	ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
	STANDARD20_MODULE_STUFF,
	NULL,
	NULL,
	NULL,
	NULL,
	NULL,
	register_hooks
};

Configuring the Project

Next we need to reconfigure the build target to create a library instead of a normal program. Right-click the build target and click “Remove”:

Remove build target

When the dialog displays, uncheck the “Also remove from disk” option before clicking “OK”. Now we need to add a new build target. Right-click the “src” folder and select “Add Target”:

Add new build target

From the “Add Target” dialog, change the type to “Libtool Library” and enter the name of the module. Also check the “-avoid-version” and “-module” options.

Add new build target dialog

As soon as the target is created, right-click on it and make sure the checked options saved properly. Right-click on the target again and select “Make Target Active”:

Make target active

Edit the project’s options by right-clicking the “src” folder and selecting “Options”:

Src dropdown menu

Since this is a C project, we want to add the following options to the “CFLAGS” field:

-DLINUX=2 -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -D_REENTRANT -pthread
Options - Compiler

From the “Includes” tab, add the following outside include directories:

  • /usr/includes/apr-1.0
  • /usr/includes/apache2
Options - Includes

Reorder the include paths so that “$(all_includes)” is first. Due to a bug or poor design, you must edit the two paths you just added and prepend a “-I”:

Include path prepend -I
Include path prepend -I

Since we deleted the old build target, we need to add the source files to the target by right-clicking the target and selecting “Add Existing Files”:

Adding files to target

From the dialog, drag and drop the files you want to be apart of the target. For this simple example, we only move the “mod_helloworld.c” file.

Adding files to target

Building the Project

We are all set to compile the project. From the “Build” menu, select “Build Active Target”:

Building the active target

If this is the first time you are performing the build, KDevelop will prompt you whether or not you want to run automake. Click the “Run Them” button to continue.

Run automake dialog

When the build is finished, the “Messages” panel will show up and display the build results. If everything went as planned, the output will say the build was successful.

Build results

Deploying the Module

The build process put the shared library file in the following location (assuming debug build):

/path/to/mod_helloworld/debug/src/.libs/libmod_helloworld

We need to install that file in the Apache modules directory which on Ubuntu is:

/usr/lib/apache2/modules

From a terminal, run the following command as root or sudo:

cp /path/to/mod_helloworld/debug/src/.libs/libmod_helloworld /usr/lib/apache2/modules/mod_helloworld.so

Next you’ll need to edit the Apache configuration file. In Ubuntu, the file is located at:

/etc/apache2/apache2.conf

You need to add the LoadModule and <Location> directives so Apache knows when to invoke the module.

LoadModule helloworld_module /usr/lib/apache2/modules/mod_helloworld.so
<Location /helloworld>
    SetHandler helloworld
</Location>

I’ve had spotty luck where to actually insert those settings. After the LogLevel, but before any other LoadModule entries seems to work for me. After you save the changes, restart Apache using the following command as root or sudo:

apache2ctl restart

If your Apache acts funny, try restarting it again.

Testing the Module

The last step is to test the module. Open up your favorite web browser and hit http://localhost/helloworld:

Hello World in Firefox

If everything worked, you should see something similar to the image above.

Where To Go From Here

We have only scratched the surface. The Apache Portable Runtime (APR) provides a ton of functionality that makes developing modules much easier. The Apache Modules Book dives into several topics such as configuration settings, content generators, filters, and database connectivity.

Another great resource is Apache’s own module source code in their Subversion repository: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/.