It is possible with Apache to host multiple websites with a single static IP address. However, you can only have one SSL certificate per static IP. This post describes setting up Apache with multiple secure virtual hosts and a single self-signed wildcard certificate. To learn about creating the certificate, check out Creating Self-Signed Certs on Apache 2.2.

Here’s a table of our example hosts:

Domain Force SSL? Trusted? Valid Domain?
www.site-a.com No No Yes
secure.site-a.com Yes No Yes
test.site-a.com No No Yes
www.site-b.com No No No
secure.site-b.com Yes No No

In order for the certificate to be trusted, you need to obtain the certificate from a trusted certificate authority. Since we are using self-signed certificates, they are not trusted and we will see some warning messages. The data will still be encrypted.

For this to work, we are going to use name-based virtual hosts.

The name and location of Apache’s configuration files vary based on which platform you use. This post assumes Ubuntu in which case the configuration files in the /etc/apache2 directory.

For starters, we need to tell Apache which ports to listen on by editing the file /etc/apache2/ports.conf.

Listen 80
<IfModule mod_ssl.c>
    Listen 443
</IfModule>

Next we need to add our virtual hosts. They are kept in the /etc/apache2/sites-available directory. For organization purposes, separate your sites into separate config files, then run a2ensite for each site to generate a symbolic link in the /etc/apache2/sites-enabled directory.

Here is the configuration for the sites:

NameVirtualHost 192.168.1.200:80
NameVirtualHost 192.168.1.200:443

# http://site-a.com
# https://site-a.com -- Throws warning because cert is for *.site-a.com... see bottom
# http://www.site-a.com
# https://www.site-a.com
<VirtualHost 192.168.1.200:80 192.168.1.200:443>
  ServerName site-a.com
  ServerAlias www.site-a.com
  DocumentRoot /path/to/www.site-a
  # Note: SSL settings only need to be defined once!
  SSLEngine On
  SSLCertificateFile /path/to/thecert.crt
  SSLCertificateKeyFile /path/to/thecert.key
</VirtualHost>

# Not SSL, redirect to https://secure.site-a.com
<VirtualHost 192.168.1.200:80>
  ServerName secure.site-a.com
  Redirect / https://secure.site-a.com/
</VirtualHost>

# https://secure.site-a.com
<VirtualHost 192.168.1.200:443>
  ServerName secure.site-a.com
  DocumentRoot /path/to/secure.site-a
</VirtualHost>

# http://test.site-a.com
# https://test.site-a.com
<VirtualHost 192.168.1.200:80 192.168.1.200:443>
  ServerName test.site-a.com
  DocumentRoot /path/to/test.site-a
</VirtualHost>

# http://www.site-b.com
# https://www.site-b.com -- Throws warning because cert is for *.site-a.com
<VirtualHost 192.168.1.200:80 192.168.1.200:443>
  ServerName www.site-b.com
  DocumentRoot /path/to/secure.site-b
</VirtualHost>

# Not SSL, redirect to https://secure.site-b.com
<VirtualHost *:80>
  ServerName secure.site-b.com
  Redirect / https://secure.site-b.com/
</VirtualHost>

# https://secure.site-b.com -- Throws warning because cert is for *.site-a.com
<VirtualHost 192.168.1.200:443>
  ServerName secure.site-b.com
  DocumentRoot /path/to/secure.site-b
</VirtualHost>

Despite having a wildcard certificate for *.site-a.com, you will get an invalid domain message when you don’t supply the subdomain (i.e. http://site-a.com). The only way I know of to solve this is with 2 static IPs and 2 certs where one cert is for site-a.com and the other is for *.site-a.com.

I’m using 192.168.1.200 for the server’s IP address behind the firewall. You could try using * instead of 192.168.1.200 in the <VirtualHost> blocks, but I haven’t tested this. Leave a comment if you happen to test this. :)

Assuming the stars have aligned, you should have several secured virtual hosts!


Here’s my presentation I gave June 9, 2008, at the Twin Cities MySQL and PHP User Group about my highly available cluster using DRBD and Heartbeat.

I added a few slides and cleaned things up a bit. The presentation went well and we had a lot of good questions.

The MySQL and PHP User Group will be taking some time off over the summer. There will be another meetup mid-summer to come up with some ideas for future meetings.


Apache has a neat module called mod_dbd that allows your Apache modules to connect to a database. mod_dbd interfaces with apr_dbd, an Apache Portable Runtime (APR) abstraction layer around database specific drivers.

Back when Ubuntu 7.04 (fiesty) was released, a MySQL driver was not bundled with Apache for licensing concerns. So, in order to use mod_dbd to connect to a MySQL database, you need to get the MySQL driver source code from WebThing (apr_dbd_mysql.c) and manually re-compile apr-utils.

You also need the source code for Apache 2.2.3 (which includes apr-utils 1.2.7) from the Ubuntu 7.04 repositories, then copy the apr_dbd_mysql.c file into the Apache source apr-utils/dbd directory. The Ubuntu guys made a nice INSTALL.MySQL file in the apr-utils with some basic instructions.

What they don’t tell you is you need to install the MySQL source. To make matters worse, once you install it, the apr-utils 1.2.7 configure script can’t find it, even if you tell it where it is.

<snip>
configure: checking for mysql in /usr/src/mysql-dfsg-5.0-5.0.38/include
checking mysql.h usability... no
checking mysql.h presence... no
checking for mysql.h... no
<snip>

This apparently was a known issue and was fixed in apr-utils 1.2.8.

Starting with apr-utils 1.2.11, the MySQL driver is bundled with it. Unfortunately, even Ubuntu 7.10 (gutsy) still ships with apr-utils 1.2.7. So, you are forced to download the source and compile.

Or, you can wait a couple days and Ubuntu 8.04 (hardy) which has Apache 2.2.8 and apr-utils 1.2.11. In theory the MySQL driver will work out of the box.

As for me, I’ll be compiling Apache, PHP, MySQL, memcached, and <insert essential infrastructure software> from source like I should have done in the beginning.


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/.


Security is a always a big concern and there’s no reason your website should go unsecure. You can secure your Apache website with a self-signed SSL certificate. This post describes the process using Apache 2.2 and OpenSSL on a Ubuntu Linux server.

Begin by generating a private key:

$ openssl genrsa -out mycert.key 1024

Next, generating a certificate request and enter the information:

$ openssl req -new -key mycert.key -out mycert.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Next, generate the self-signed certificate. You can specify the number of days the cert is valid for.

$ openssl x509 -req -days 365 -in mycert.csr -signkey mycert.key -out mycert.cert
Signature ok
subject=/C=/ST=/L=/O=/CN=
Getting Private key

You no longer need the .csr request file. Create a folder and move the .key and .cert files into it:

$ sudo mkdir /etc/apache2/ssl
$ sudo mv *.cert /etc/apache2/ssl
$ sudo mv *.key /etc/apache2/ssl
$ sudo chmod 400 /etc/apache2/ssl/*.key

If the cert is protected with a password, by default Apache will prompt for the password when it starts. This can be a problem since you will need to enter the password each time Apache is restarted. We can fix this by having Apache call a program that returns the password.

Create the shell script /etc/apache2/ssl/password.sh and enter the following:

#!/bin/bash
echo “password”;

Next we need to tell Apache to run the script. Apache’s SSL settings are stored in:

/etc/apache2/mods-enabled/ssl.conf

Edit the file and change the SSLPassPhraseDialog to:

SSLPassPhraseDialog exec:/etc/apache2/ssl/password.sh

The last step is to assign the certificate to your Apache site by editing the sites file:

/etc/apache2/sites-enabled/000-default

You’ll need to configure the SSL settings for the site:

<VirtualHost 192.168.1.100:443>
        ...
        SSLEngine on
        SSLCertificateFile /etc/apache2/ssl/mycert.cert
        SSLCertificateKeyFile /etc/apache2/ssl/mycert.key
        ...
</VirtualHost>

Don’t forget to tell Apache to listen on port 443 in the /etc/apache2/ports.conf file. Restart Apache with sudo apache2ctl restart and you should be a little closer to being secure.


Recently I needed to generate a self-signed SSL cert for Apache Tomcat 5.5 on my Ubuntu Linux server. The basic process is to create a Java keystore with the self-signed cert, change Tomcat’s configuration file, and restart the server. Here’s how I did it:

$ keytool -genkey -alias tomcat -keyalg RSA -keystore mycert.jks
Enter keystore password:  changeit
What is your first and last name?
  [Unknown]:  Chris Barber
What is the name of your organizational unit?
  [Unknown]:
What is the name of your organization?
  [Unknown]:  CB1, INC.
What is the name of your City or Locality?
  [Unknown]:  Minneapolis
What is the name of your State or Province?
  [Unknown]:  MN
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Chris Barber, OU=Unknown, O="CB1, INC.", L=Minneapolis, ST=MN, C=US correct?
  [no]:  yes

Enter key password for <tomcat>
        (RETURN if same as keystore password):

By default, Tomcat will assume the password as “changeit”. You can change the password, but then you need to set the keystorePass in Tomcat’s configuration file. Regardless, the password for both the keystore and the cert MUST be the same. Store the keystore in a safe place such as Tomcat’s configuration folder:

/etc/tomcat5.5

Next edit Tomcat’s server configuration file:

/etc/tomcat5.5/server.xml

Locate the SSL connector declaration, uncomment it, and add the keystoreFile path:

<!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
<Connector port="8443" maxHttpHeaderSize="8192"
        maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
        enableLookups="false" disableUploadTimeout="true"
        acceptCount="100" scheme="https" secure="true"
        keystoreFile="/etc/tomcat5.5/mycert.jks"
        clientAuth="false" sslProtocol="TLS" />

Save the changes and restart Tomcat:

$ sudo /etc/init.d/tomcat5.5 restart

You should be good to go at this point. Launch your favorite web browser and go to https://localhost:8443.

SSL dialog

Now you are secure and ready to rock.