Edit: Geez. Since I set up this post, I noticed that the compaq8000.conf example was missing small bits like oh, the mod_gnutls parts. This update now contains the missing portion.
I’d read Ipstenu’s blog post “Request: Multiple Domains, One IP SSL Certificates” and thought that that shouldn’t be too hard. Simply put, this is a request for the configuration of an Apache web server to be able to distinguish between requested SSL sites but with only one IP address being used.
Virtual hosts on Apache is a real resource saver. With just one server you can have as many different websites and on this server I have at least 4 running. But in order to get it working Apache must support Server Name Indication. You can read up on SNI at Wikipedia for more details.
I use Ubuntu LTS because it’s got long term support and has features that I like. But I had previously been a RedHat user from RedHat 4.0 and on. Using RPM I would roll my own packages for work and hobby. How hard can it be to setup CentOS 5.6 on one of my spare PCs?
It turned out that that was sort of true for me and after some trial and error I got it working with gnutls. I’ve been using Ubuntu LTS for so long that my RHEL (CentOS) experience is dated. I was able to get multiple SSL based virtual hosts working on a CentOS 5.6 but that involved unwittingly updating to CentOS 5.7 without realizing it, and I also had to enable the CentOS testing repo.
Installing CentOS and add the testing repo
First get CentOS 5.6 installed. I have an old Compaq Presario 8000 in the basement for playing around so I torrented the CentOS 5.6 DVD and did a plain server install.
Once installed, I ran the following commands to bring the fresh installation up to speed.
yum update
chkconfig --add httpd
chkconfig --del iptables
reboot
That upgraded about 120 RPMs and took longer than the initial install but I was updated unknowingly to CentOS 5.7! The next 2 commands added Apache2 to be started up automatically and shut off iptables. I didn’t want to play with firewall rules and I set SELINUX=disabled in /etc/sysconfig/selinux.
My basement server is 192.168.1.9 and I put in 2 names into my internal DNS server jan-basement and compaq8000. I created two new self-signed certificates for those two names and put the new files into the /etc/pki/tls/certs and /etc/pki/tls/private directories.
I could have rolled my own mod_gnutls RPM but I prefer to use packages created by CentOS. To do that I had to edit the /etc/yum.repos.d/CentOS-Testing.repo file and change enable=0 to enable=1.
[ c5-testing]
name=CentOS-5 Testing
baseurl=http://dev.centos.org/centos/$releasever/testing/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://dev.centos.org/centos/RPM-GPG-KEY-CentOS-testing
# CentOS-Testing:
# !!!! CAUTION !!!!
# This repository is a proving grounds for packages on their way to CentOSPlus and CentOS Extras.
# They may or may not replace core CentOS packages, and are not guaranteed to function properly.
# These packages build and install, but are waiting for feedback from testers as to
# functionality and stability. Packages in this repository will come and go during the
# development period, so it should not be left enabled or used on production systems without due
# consideration.
See that caution? That’s the part that worries me because the c5-testing repo is where I found the mod_gnutls RPM. I believe using that RPM should be fine but check with CentOS support forums.
Install the mod_gnutls RPM and create configs
Once you enable that repo, perform the following commands as root:
# Install the mod_gnutls RPM via yum
yum install mod_gnutls
# Create the sym-link for the module
ln -s /usr/lib/httpd/modules/libmod_gnutls.so /etc/httpd/modules/mod_gnutls.so
# Rename the ssl.conf to ssl.conf-old. This will disable mod_ssl from loading.
mv /etc/httpd/conf.d/ssl.conf /etc/httpd/conf.d/ssl.conf-old
Next up, create the configuration files and directories for your vhosts. I like to place my vhosts into /var/www/vhosts.
mkdir -p /var/www/vhosts/jan-basement
mkdir /var/www/vhosts/compaq8000
Create a conf file for each vhost and put these lines into them:
<VirtualHost 192.168.1.9:80>
ServerName compaq8000
ServerAdmin webmaster@localhost
DocumentRoot /var/www/vhosts/compaq8000/
<Directory />
Options FollowSymLinks -Indexes
AllowOverride All
</Directory>
ErrorLog /var/log/httpd/compaq8000-error.log
LogLevel warn
CustomLog /var/log/httpd/compaq8000-access.log combined
ServerSignature On
</VirtualHost>
<VirtualHost 192.168.1.9:443>
GnuTLSEnable on
GnuTLSCertificateFile /etc/pki/tls/certs/compaq8000.crt
GnuTLSKeyFile /etc/pki/tls/private/compaq8000.key
ServerName compaq8000:443
ServerAdmin webmaster@localhost
DocumentRoot /var/www/vhosts/compaq8000/
<Directory />
Options FollowSymLinks -Indexes
AllowOverride All
</Directory>
ErrorLog /var/log/httpd/compaq8000-ssl_error.log
LogLevel warn
CustomLog /var/log/httpd/compaq8000-ssl_access.log combined
ServerSignature On
</VirtualHost>
I repeated the same with the other vhost but replaced the compaq8000 with jan-basement.
The RPM puts /etc/httpd/conf.d/mod_gnutls.conf with all the lines commented out. Rather than play with that file, I just created a small new file /etc/httpd/conf.d/fix-up.conf with these lines in it.
ServerName jan-basement
NameVirtualHost 192.168.1.9:80
NameVirtualHost 192.168.1.9:443
LoadModule gnutls_module modules/mod_gnutls.so
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
Listen 443
You can probably leave out the ServerName and the NameVirtualHost on port 80. My home DNS is not a robust as it could be…
Now re-start httpd with a simple “service httpd restart”. If all goes well, and your DNS is setup correctly, then you should now have two virtual hosts that serve out the correct different SSL certs for each one,
You couldn’t get it working with mod_ssl?
I couldn’t get it working reliably. With initial installation of CentOS I was able to get Apache2 to reply back with the correct SSL certs. But after I tore it all down and re-did it again, I got inconsistent results. On my Ubuntu LTS servers (which this blog runs on) I had a similar issue and I think that’s why I use mod_gnutls today. It works reliably and I’ve had no issues with multiple SSL certificates on one IP address.
Caveats
This worked out on my unused basement server but there are several concerns I have.
1. CentOS 5.6 updates to 5.7 (final) when I did yum update
That was a shock to me. I get that CentOS wants to keep things current but I had thought that I would be updating within the 5.6 branch. On my PC going to 5.6 may not be a big deal but if you run a VPS make sure you can restore you backup and check with your host provider. It should be fine but gotchas on production servers is a huge no-no.
2. Adding the CentOS Testing repository
The nice thing about using pre-made packages is that you don’t personally have to maintain them. If Apache2 gets an update will this RPM work continue to work? It depends on how the module is compiled. It might be safer to find a good mod_gnutls SRPM and keep that ready to be built a a just in case.
3. Backups are your friend
CentOS stores it’s Apache2 configs in /etc/httpd and before anyone tries this at a minimum they should keep fresh copies of that directory somewhere safe.
That seemed like a lot of work for your curiosity
Nah! While solving problems like this is part of my day to day work routine, this has always been my hobby. Some people work in their wood shop, I work on my software configs and these sorts of problems are fun. And now I’m more up to date with CentOS as a result.
Doing this with Ubuntu LTS is much easier because the software is supported right out of the box. SNI on Ubuntu is just a matter of configuration and all the necessary software is part of the distribution. But if you are going to use CentOS and want SNI to work, then this could work out for you.