Posted by Murat Ayfer

* This blog post is part of Invoke’s participation in the 2008 Vancouver Blogathon for Charity

I keep seeing blogs and forum threads about hosting multiple SSL sites on a server that has a single IP number, and there seems to be a lot of confusion on this topic. When people ask if this is possible, others simply respond “No”, or advise them to use different ports. But we found a workaround.

The reason for why different certificates cannot be used for different virtual hosts (on the same IP/Port) is explained in the Apache documentations. The wording in this documentation makes it sound like you can’t have SSL virtual hosts, but it’s actually just talking about having multiple certificates. If you go ahead and try setting up different SSL certificates for your virtual hosts, you will see that the certificate from the first virtual host that Apache finds will be used for all of your SSL virtual hosts. So if you have one certificate that covers all your domains, everything should work fine on a single IP/Port. In fact, this is exactly what happens with wildcard certificates. However using wildcards still forces you to use a single domain, even though you can have multiple subdomains on the same certificate. If you want to be able to have multiple domains, the solution is to use a Unified Communications Certificate (UCC, a.k.a SAN certificate).

We got our UCC from DigiCert, and they allow up to 150 different domains on one certificate. This is more than enough for us. I was also surprised to see that pretty much all browsers support this certificate. In fact, Microsoft has been supporting it since Windows 98.

Here at Invoke, we recently set up an Amazon EC2 instance to host some of our websites on. Since Amazon only allows one IP per instance, this was a perfect solution for us. The only problem was that we are using ISPConfig on our webserver, and we had to hack it a little bit to allow using the same certificate for all SSL domains. Here are the steps we went through to get our SSL domains up and running:

  1. Getting the certificate
    We decided to go with DigiCert since they have really good customer support. It cost us $80/domain for the first four, and $40 for any additional domain after that. Considering how much of a life saver this certificate is, I think this is a decent price. One other thing I really like about the UCC is that new domains can be added at any time after you get the certificate. All you need to do is reissue, and overwrite your old certs with the new ones. Once you get the certificate, there are three essential files you need:
    • yourdomain.key – this is the key file which you generated when you were creating the request certificate.
    • yourdomain.crt – this is the primary certificate they gave you
    • DigiCertCA.crt – this is the intermediate certificate that makes browsers recognize DigiCert as an authority

    I usually keep these in /etc/apache2/ssl/, but really you can put them wherever you want, as long as you reference them correctly in your apache configurations.

  2. Installing ispconfig
    We are running Ubuntu Server 7.10 (x86_64) on our web server, and below are the commands that install ISPConfig’s dependencies.
    1. # apt-get install libdb4.5-dev ncftp lynx openssl-devel quota libmysqlclient15-dev libmysql++-dev flex bind9 postfix procmail build-essential
    2. # perl -MCPAN -e shellYou will be asked a bunch of questions, just follow all the instructions here. When you get the CPAN shell, run these commands:
      CPAN> install HTML::Parser
      CPAN> install Net::DNS
      
      CPAN> install Digest::SHA1
      CPAN> install DB_File
    3. # ln -sf /bin/bash /bin/sh
    4. And then simply run the ISPConfig installation, and follow the instructions.
  3. Hacking ispconfig to allow multiple SSL sites on one ip/port
    1. Edit the file ispconfig/scripts/lib/config.lib.php
    2. Find the parts that say (there are two!):
           //////////////////////////////////////////////////////
           // Check ob bereits ein SSL Cert auf der IP Existiert
           //////////////////////////////////////////////////////
           $ssl_count = $go_api->db->queryOneRecord("SELECT count(doc_id) as ssl_co
           if($ssl_count["ssl_count"] > 1) {
              // Es existiert bereits ein SSL Web mit dieser IP
              $status = "NOTIFY";
              $errorMessage .= $go_api->lng("error_web_ssl_exist");
              $go_api->db->query("UPDATE isp_isp_web set web_ssl = 0 where doc_id =
           }

      And comment them out. (Thanks to this HowtoForge article) This will stop ISPConfig from giving an error message when you try to add a second SSL domain on the same IP.

    3. Find the line that says:
              $mod->tpl->assign( array(SERVERIP => "NameVirtualHost ".$ip["server_ip"].$web_port."

      And change it to:

              $mod->tpl->assign( array(SERVERIP => "NameVirtualHost ".$ip["server_ip"].$ssl_port."
      NameVirtualHost ".$ip["server_ip"].$web_port."

      So you’re basically adding in another line to the string with the $ssl_port instead of $web_port

    4. Find the two lines:
      SSLCertificateFile ".$mod->system->server_conf["server_path_httpd_root"]."/web".$web["doc_id"]."/ssl/".$web["web_host"].".".$web["web_domain"].".crt
      SSLCertificateKeyFile ".$mod->system->server_conf["server_path_httpd_root"]."/web".$web["doc_id"]."/ssl/".$web["web_host"].".".$web["web_domain"].".key
    5. And change them to:
      SSLCertificateFile /etc/apache2/ssl/yourdomain.crt
      SSLCertificateKeyFile /etc/apache2/ssl/yourdomain.key
      SSLCertificateChainFile /etc/apache2/ssl/DigiCertCA.crt

      This will force every SSL domain to use these hard-coded certificates. And of course, make sure these are your shared UCC certificates. (yourdomain.crt is the Primary certificate, yourdomain.key is the Key file, and DigiCertCA.crt is the Intermediate certificate.)

  4. Configuring ISPConfig
    Go to Management -> Server -> Settings -> IP list, and add “*”. When you are adding sites, be sure to choose * as the IP, otherwise virtual hosts will not work.
  5. If you are not using ISPConfig
    The Apache configurations are pretty straightforward. You can set up your virtual hosts on port 443, just as you would for non-SSL domains. The only difference is that for each virtual host, you will have these three lines:
    SSLCertificateFile /etc/apache2/ssl/yourdomain.crt
    SSLCertificateKeyFile /etc/apache2/ssl/yourdomain.key
    SSLCertificateChainFile /etc/apache2/ssl/DigiCertCA.crt

    So your configuration file will look something like this:

    NameVirtualHost *:443
    NameVirtualHost *:80
    <VirtualHost *:80>
      # non-ssl domain
      ...
    </VirtualHost>
    
    <VirtualHost *:443>
      # ssl domain
      ...
      SSLCertificateFile /etc/apache2/ssl/yourdomain.crt
      SSLCertificateKeyFile /etc/apache2/ssl/yourdomain.key
      SSLCertificateChainFile /etc/apache2/ssl/DigiCertCA.crt
    </VirtualHost>
    
    

That’s it!