Nginx – How to serve multiple SSL certificates for the default virtual host on NGINX

nginxsnissl

I have a static app on Amazon S3 that is served through a NGINX proxy. The purpose I use a proxy is to allow users to point their domains to my Amazon EC2 instance (via CNAME record pointing to custom-domain.myproduct.com) so they can access my app via their own custom url like this: myproduct.happyclient.com.

To achieve this I have the following nginx configuration (parts removed for brevity):

http {
    server {
    # This is my default route. References:
    # http://stackoverflow.com/a/15799883/91403
    # http://nginx.org/en/docs/http/request_processing.html

    listen 80 default_server;
    server_name custom-domain.myproduct.com;
    location / {
        proxy_pass http://static.myproduct.com; # points to Amazon S3
        proxy_set_header Host myproduct.com;
    }
}

Even though my static app is 100% public (no client secret, only html and javascript) some of my clients want to access it though SSL. How can I dynamically choose which certificate to use for the SSL connection based on the Host header? Note that I can't simply hardcode the cert path.

PS.: Clients will be able to upload their certs to my instance
PS2.: This setup already works perfectly with HTTP only.

What I have tried

I have tried something like this, with no success:

server {
    listen 443 default_server;
    server_name custom-domain.myproduct.com;
    ssl on;
    ssl_certificate /etc/nginx/ssl/$http_host/server.crt; # note the http_host variable
    ssl_certificate_key /etc/nginx/ssl/$http_host/server.key; # also here
}

Best Answer

How can I dynamically choose which certificate to use for the SSL connection based on the Host header?

The Host header is part of the HTTP protocol, but HTTPS is HTTP embedded into a SSL connection. Which means you first have to establish the SSL connection (which needs the certificate) before you have access to the Host header.

If the client supports SNI (all modern browsers do, but IE/XP not) it will send the target name inside the SSL handshake already. Providing different certificates based on the target name is usually done with different server sections in nginx. You might try to use the $ssl_server_name within the default section but I'm not sure that this will work and even if this works it might affect optimizations like session caching in a negative way.