11 June 2010

How To: Two SSL Domains on One Amazon EC2 Instance

First, I want to apologize to my regular readers for this post. This is not what you come here to see. Alas, I just spent many hours trying to find a way around a problem whose solution does not fully exist yet on the internet. I needed to put this out there for anyone else who may need it in the future.

The Problem: Amazon EC2 instances only allow you to assign one IP address per instance, so it is almost impossible to serve two different domains with two different SSL certificates from the same instance. There is a workaround that exists out there on the internet, which was written 6 months ago, but it fails to explain a few crippling details that will take you hours to figure out and Amazon has also slightly changed their interface since then. Hopefully this tutorial will smooth things out for a while.

The Setup: The instance in question is running Fedora with a LAMP stack. The system is running on mostly default settings. There are two domains, domain1.com and domain2.com. I don't have a solution for three or more.

I'm assuming, with this tutorial, that you already know how to work with Apache settings to create virtual hosts or that you have access to someone who does.

The Solution:
Step 1: If you haven't done it, create an Elastic IP in the Amazon Management Console and assign it to your instance. Then, point domain1.com's DNS (A record) to the IP. I don't know what happened, but in the middle of working, the amazon instance just changed its public DNS location. Assigning this Elastic IP will ensure that it doesn't burn you like it did me.

Step 2: In your Amazon Management Console, create an Elastic Load Balancer. Forward port 80 to 80 and forward port 443 (https) to 8443. You can actually choose any viable port of your liking, but I used 8443 to follow the aforementioned solution. Point the ELB to your instance. Then, point domain2.com's DNS (CNAME record) to the ELB's DNS name.

A note about ELB: It costs extra money. It's not a lot, but it is extra.

Step 3: Edit your instance's security group to allow both ports 443 and 8443.

Step 4: Edit /etc/httpd/conf.d/ssl.conf
Below:
Listen 443
Add:
Listen 8443

By default ssl.conf has a default VirtualHost declaration for port 443. Change the following values within it to whatever they need to be to run your SSL:
<VirtualHost _default_:443>
ServerName www.domain1.com
ErrorLog logs/domain1_ssl_error_log
TransferLog logs/domain1_ssl_access_log
LogLevel warn
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
SSLCertificateFile /var/www/ssl/domain1.crt
SSLCertificateKeyFile /var/www/ssl/domain1.key
SSLCACertificateFile /var/www/ssl/verisignssp.crt
SetEnvIf User-Agent ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

At the bottom of the file, add an identical section, but change the port and the relevant values to suit domain2.com:
<VirtualHost _default_:8443>
ServerName www.domain2.com
ErrorLog logs/domain2_ssl_error_log
TransferLog logs/domain2_ssl_access_log
LogLevel warn
RequestHeader set X_FORWARDED_PROTO 'https'
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
SSLCertificateFile /var/www/ssl/domain2.crt
SSLCertificateKeyFile /var/www/ssl/domain2.key
SSLCACertificateFile /var/www/ssl/verisignssp.crt
SetEnvIf User-Agent ".*MSIE.*" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

Step 5: Wait for DNS to propagate, restart Apache, cross your fingers.

2 nibbles:

  1. *ahem* . .

    http://en.wikipedia.org/wiki/Server_Name_Indication#Browsers
    ReplyDelete
  2. Using Server Name Indication will still not work for a decent percentage of users. Probably a few years more before it's in the high 90% acceptance range. This solution seems more practical until that point.
    ReplyDelete