
Ever needed to setup virtual hosts in nginx? Thankfully it’s quite simple. Ever had to have each of those virtual hosts support nginx+SSL/HTTP? Well then things start to get a little tricky, well so I thought. Turns out it’s just as easy, but with a few caveats.
Configuring nginx for SSL (nginx+ssl) virtual hosts (hosting multiple secure sites on one IP!)
The additional section you need to add to your nginx config is this:
server {
listen 443;
server_name myserver.com;
ssl on;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
# put the rest of your server configuration here.
location / {
proxy_set_header X-FORWARDED_PROTO https;
# put your config here
}
}
The only differences here over your standard non-SSL setup is the port you are listening on, the 3 ssl*_ lines, and setting the header so that mongrel/rails knows that this is a HTTPS request. You’ll have noticed that we make reference to a certificate and key. If you’ve got an externally facing public server you’ll probably want to get them from a proper issuing and certification body such as VeriSign. You can however create your own self-signed certificate so we can test it out.
Creating a self-signed SSL certificate
Creating a self-signed certificate for testing is quite simple, but you’ll need to ensure you have openssl installed. (If you don’t, there are instruction for installing openssl as part of my apache installation guide )
openssl req -new -x509 -nodes -out server.crt -keyout server.key
This will generate the server.crt and server.key files referenced above. I should point out that server.key won’t have a passphrase, so don’t use it on anything beyond testing. To add a passphrase you can run the following:
openssl rsa -des3 -in server.key -out server.key.new
And then move the new key to where you needs it to be.
Beware the caveats!
Seemed to easy? You’re right. You need to ensure you’ve got a recent(ish) version of nginx, at least greater than 0.5.35 as it was the first to include support for TLS SNI (transport layer security server name identification). You’ll also need to have compiled it with a version of OpenSSL with the TLS Extension (enable-tlsext directive). The biggest downside in my book though, is that you’re dependent on support at the client end for it to work. And at present, that support is limited to:
- Firefox 2.0 and greater
- Internet Explorer 7.0 and greater
- Opera 8.0 and greater
That’s right, no support at all for Safari users.
Hosting multiple secure sites on one server
So what to do if you want to have support for all browsers? You’re back to having to have a one-to-one mapping between sites and IP addresses. You nginx config will be similar to the one above, except that you’ll remove the server_name directive and listen directly to a specific IP address:
server {
listen 192.168.1.20:443;
ssl on;
ssl_certificate /etc/nginx/certs/server.crt;
ssl_certificate_key /etc/nginx/certs/server.key;
# put the rest of your server configuration here.
location / {
proxy_set_header X-FORWARDED_PROTO https;
# put your config here
}
}
So it’s probably going to be a few years before we can comfortably host multiple secure sites on the one IP address.