One of the complaints about EC2 is that you only have one IP address allocated per instance which makes it difficult to host, in a clean manner, multiple domains that require SSL certs. Where you have control over IP allocation you could punch down a couple for one server and then set up your domains and SSL certs by IPs. That method is a no go so you are left with the ugly method of allocating those certs by port, something that Joe and Jane public are a little skittish about (https://superawesomefuntime.com is cool but https://superawesomefuntime.com:8443 smells phishy). Thankfully, ELB makes for a great proxy to hide the hideousness of the port-based workaround.
Essentially, as solutions go, this one is stupid easy; for each domain that you need to handle SSL for create a load balancer. Many balancers to one or a pool of instances. That’s it. Here’s a sloppy diagram…
For this example, we’ll be serving superawesomefuntime.com and unicorns-unlimited.com:
elb-create-lb superawesome --headers --listener "lb-port=443,instance-port=8443,protocol=TCP" --listener "lb-port=80,instance-port=80,protocol=http" --availability-zones us-east-1c
elb-create-lb unicorns --headers --listener "lb-port=443,instance-port=8445,protocol=TCP" --listener "lb-port=80,instance-port=80,protocol=http" --availability-zones us-east-1c
Take note of the address which are returned to you as need that for the cname portion of the game. They’ll look something like this: superawesome-123456789.us-east-1.elb.amazonaws.com and unicorns-987654321.us-east-1.elb.amazonaws.com.
The next step would be to add your instance to those load balancers:
elb-register-instances-with-lb superawesome --instances i-12ab3c45
elb-register-instances-with-lb unicorns --instances i-12ab3c45
Over on the server set up your virtual hosts in a way that hopefully is as hasty as mine…
NameVirtualHost *:8443
<VirtualHost *:8443>
ServerName superawesomefuntime.com
ServerAlias *.superawesomefuntime.com
SSLEngine On
SSLCertificateFile /etc/ssl/superawesome.crt
SSLCertificateKeyFile /etc/ssl/superawesome.key
RequestHeader set X_FORWARDED_PROTO 'https'
## Directories, Includes, Rewrites, oh my...
</VirtualHost>
<VirtualHost *:8445>
ServerName unicorns-unlimited.com
ServerAlias *.unicorns-unlimited.com
SSLEngine On
SSLCertificateFile /etc/ssl/unicorn.crt
SSLCertificateKeyFile /etc/ssl/unicorn.key
RequestHeader set X_FORWARDED_PROTO 'https'
## Directories, Includes, Rewrites, oh my...
</VirtualHost>
Then all you need to do is set up the cname for each domain to point at the load balancer address, in this example the cnames would be for *.superawesomefuntime.com = superawesome-123456789.us-east-1.elb.amazonaws.com and *.unicorns-unlimited = unicorns-987654321.us-east-1.elb.amazonaws.com.
The only loose end is configuring your healthcheck but that is a deeply personal decision best left for you and your app to work out.


Beautiful use of ELB for getting around an annoying limitation of EC2 – only one IP address per instance.
I’ll be referring people to this article!
Thanks! This was one of those “wake up in the middle of the night asking yourself, ‘Can I do that?’” moments. Definitely happy that one of the more frustrating EC2 limitations is easily solved.
Actually the vast majority of punters probably don’t even notice that (even though it might smell a bit to you or I). The real drawback is that a lot of corporate firewalls block anything but port 80 and 443 for web access and you find that significant numbers of people can’t get to the SSL part of your site.
I documented doing the port-based approach in detail on my blog but pulled the post when I found we were getting people complaining about not getting to our site. I ended up just going with a multi domain cert but the technique you describe looks like the best of both worlds.
Hmm, well as I understand it ELB is acting as a reverse-proxy much as if you dropped Nginx or HAProxy in front of your web servers to act as a balancer, all the traffic flows through the balancer on it’s foward facing ports. The whole process should be transparent to the end user. Were the people complaining that they could reach your site able to prior to implementing ELB? It has been several years since I was managing a corporate firewall but we implemented also a content filter that had white/black list domains and that changed on a fairly regular basis.
To see how all this was operating I performed a quick test using ufw/iptables locally and operating in a restricted mode:
sudo ufw default deny
sudo ufw allow out 53,137,138/udp
sudo ufw allow out 80/tcp
sudo ufw allow out 443/tcp
sudo ufw deny out to any
sudo ufw enable
Unsurprisingly, ports 8443 and 8445 on the raw instance address failed (browser timed out) but hitting them on 443 using the cname or the elb address worked. Granted this is a terribly unscientific method but it bears out the assumption that ELB is acting as a reverse proxy though it is worth digging up some testers behind corporate firewalls.
Good article, though not exactly what i was looking for, but something i have pondered and will be implementing and linking to in the near future.
I should mention, if you came across this article while looking for a way to actually enable 443 or any other port, other then 80 and 22 on your instance (and probably got completely lost, because you are just getting started), hit up for a quick amazon tools setup tutorial amongst which lingers the command to enable 443 on your instance (or 8443 or 8445, or whatever port) http://paulstamatiou.com/how-to-getting-started-with-amazon-ec2
You should be able to secure those ports through your amazon tools with ec2 tools too, no?
ec2-revoke default -p 8443
this way if you have a group of servers you are doing this with, you could manage them all at the same time…
– Niksoft
Well, ELB operates outside the EC2 firewall so port 8443 needs to be open for it to communicate to it. It is likely possible to limit it to the ELB firewall IP range but I have seen mine shift a bit so I’m not too comfortable closing it that tight.
Wish you were showing how to do this with unicorn (http://unicorn.bogomips.org/) I keep coming back to this site looking for info on using unicorn! Names are just too overloaded on the ‘net…
Ha! Well, glancing over the Unicorn docs it seems that it should be fairly straight forward though it would seem that you need to drop in something like Nginx or Apache to handle the SSL portion of things, so if that’s the case it’s just a matter of changing the listener for each domain you’d want to serve.
Unfortunately ELBs are not usable in production websites. They incur far too much latency (up to 2 second spikes) and fail pretty frequently, far more then AWS reports.
[...] http://elwoodicious.com/2009/12/23/using-elb-to-serve-multiple-domains-over-ssl-on-ec2-for-giggles/ [...]
That sounds like a great approach. I have a question about how you would handle DNS for this though. I normally like to redirect example.com to http://www.example.com in Apache so that both are usable. This would require that I pass example.com to ELB but if I remember correctly your root DNS record cannot point to a CNAME. Thanks for any insights!
We are using Zone Edit and the way we handled this was to set up a web forward for the root to www to get around that issue.
Thanks!!
Thanks for the post James. One issue I’m running into is that I cannot assign a CNAME record for my root domain to point to the ELB host. In the context of your tutorial, I want my DNS to point superawesomefuntime.com to the CNAME superawesome-123456789.us-east-1.elb.amazonaws.com . This is possible for the subdomain “www” but as far as i know it’s not possible for the root of the domain. This means that https://www.superawesomefuntime.com would work but https://superawesomefuntime.com would not work. Got any ideas?
As I understand the DNS RFC (shaky at best!), the root record need to be an A record and that CNAMEs require no other entries with the same name. Here’s the two resources I’m getting this from: Why can’t I create a CNAME record for the root record? and RFC1034 – Domain names – concepts and facilities (compelling title…). That said, trawling the EC2 boards indicates that AWS is at least mulling the idea of allowing ELB to have static IPs which would go a long way to solving the whole RR issue.
tl;dr — I have no tricks for forcing a CNAME as a RR.
This only allows one additional SSL site on the box because an instance can only be assigned to a load balancer once.
Therefore, a multi-domain certificate is still the only answer at this time for hosting more than 2 SSL sites on one server.
We use multiple ELB’s to do this.
@james: Are you saying that you are able to create more than one ELB that points to the same EC2 Instance?
Correct, just like in the example we are using multiple ELBs and CNames in front of several instances running apache. Each instance is joined to each ELB with port 443 mapping to the corresponding port for that wildcard cert (ie superawesomefuntime.com has an ELB listener of 443 mapping to 8443 and unicorns-unlimited.com has an ELB listener of 443 mapping to 8445).
To handle failure we scripted an up or down state for port 80 which ELB is listening to for the health check, if our app fails then that health check will fail and the server is pulled out of all the balancers. For example:
elb-configure-healthcheck superawesome –headers –target “HTTP:80/health” –interval 5 –timeout 4 –unhealthy-threshold 2 –healthy-threshold 2
That will have ELB check http://ec2-public-address:80/health and if it returns anything other than 200 it stops serving traffic from it. We also use this method to do rolling deploys through the stack while still keeping the site online.
Thank You!!!
We definitely use the command line tools for a lot of things, but I never tried to create an ELB from the CLI tools. We were using the Amazon Control Panel web app to create our load balancers. In the AWS control panel, when you try to create an ELB it will only show you instances that are not already assigned to a load balancer. So we just assumed it couldn’t be done.
Thanks to your post, I created a new ELB using the CLI tools and was able to do just that!
In case anyone is interested, we were previously using this method with a multi-domain certificate: http://blog.revolunet.com/index.php/reseau/administration/hosting-multiple-ssl-vhosts-on-a-single-ipportcertificate-with-apache2
This is one of those cases where the CLI tools offer more functionality than the AWS console or Elasticfox. Glad it worked out for you, though!