Multi-domain certificate on nginx and postfix

Basicly for average webhosting HTTPS sites there are 3 kinds of certificates: Single-domain, Wildcard or Multi-domain. Here I will explain how they are different for normal use and how to get and implement the awesome and completely free multi-domain certificate from Let’s Encrypt on your nginx and postfix installations.

Certificate types

Single-domain is your old-school TLS certificate. You generate a CSR file with the Common-Name (CN) set to your domain and your CA returns you a signed certificate for your domainname and often also the ‘www’ prefix. Ranging from $30 to $100 per year.

Wildcard is the one that matches only the subdomains by setting the CN to *.hostname hence the wildcard naming. To include the main hostname you need to include it in the CSR’s Subject Alternative Name field or SAN in short. Pretty much the same as a single-domain cert but quiet costly, from $90 to $400 on each yearly renewal.

Multi-domain or SAN (Subject Alternative Name) is a certificate that validates on all included hostnames. You have to include the CN hostname in the SAN list and for the free Let’s Encrypt it’s limited to 100 hostnames. Most paid SAN-certificates are limited to only 3 hostnames around $30 a year and they charge $10 per year for each additional one. They can be hostname and sub.domain, but really you can add any hostname you like if you wish to use one certificate for multiple sites. Before SNI came around this was the only way to secure multiple domainnames on one shared IP-address.

— SNI (Server Name Indication)

Then there is SNI or Server Name Indication. Without SNI-support the webserver receives the requested domainname in the Host-header only after the certificate exchange, because that’s when the headers are sent. Therefore you could only have one certificate per IP-address. With SNI however, the browser sends the hostname it wants during the handshake before the actual encryption happens. Then the webserver can select and send over the certificate that matches the requested hostname. This is pretty cool because each site can have it’s own certification while you still have only one IP-address to share with all of them.

The downsite of SNI is that is not supported by any Internet Explorer on Windows XP, the default browser in Android 2.3 and earlier, Safari in iOS 3 and before and Java 6 and 7. But then again, those are way to vulnerable to be still around! Using them would totally undermine the HTTPS security anyway.

Another minor problem could be the fact that the requested hostname is sent to the server unencrypted. An attacker or logger somewhere along the route could see which domainname you requested. I say minor because without SNI even though the attacker can’t see the requested hostname, they can simply call the IP and get the same certificate you requested, including the actual hostname. So nothing really changes on privacy.

Certificate

These instructions assume you have Ubuntu 16.04 installed with nginx and Postfix. They also help you pass the Qualys SSL Server Test.

— Install Let’s Encrypt

First install Let’s Encrypt:

sudo apt install letsencrypt

Yep that was all it takes, now create the certificate. The one I’ll generate is for this domain ‘frankl.in’ and its www prefix.

— Generate DH param file

You need to generate strong DH parameters. For now (2016) setting 2048 bits should be fine. Lower values are already cracked or are going to be pretty soon. However, higher values might slow down the load time of your website a lot on slow devices.

sudo openssl dhparam -out /etc/ssl/dhparam.pem 2048

— Generation command

It is important to note that the first domain of the list will be the certificate’s Common Name or CN. That is the domain you see first when you click the lock in a browser to view the HTTPS details.

Also make sure the /.well-known path is not blocked by the nginx config. Let’s Encrypt stores a validation file there that it attempts to access on port 80 from a remote server during the certificate creation process.

--rsa-key-size 4096 — Set the private key size to 4096 bits which is very secure and required given all the recent breaches. Nowadays 2048 is the minimum by standards and is expected to get cracked soon while anything lower is already cracked.

--email [email protected] — You will receive important certificate-related notices on this address.

--webroot — We are going to specify website paths and their domains. This will write the verification file to /home/site1/public/.well-known/ for the verification server to access, but only for the hostnames frankl.in and www.frankl.in.

-w — The path where the website’s public files are.

-d — Include a hostname (domainname) for this site.

— Include multiple sites

Now the interesting part is you can include multiple sites in one singular certificate! Example:

This will include all these hostnames in the certificate and write the verification file to /home/site1/public/.well-known/ for frankl.in and related and write the file to /home/site2/public/.well-known/ for myhostname.net and its subdomains.

When everything went okay it will tell you where the certificate is stored, that will be /etc/letsencrypt/live/frankl.in/fullchain.pem in my example. The domain in the path is again the Common Name (CN), the first hostname in your list.

— Scripting

When you run this command it should present you the Let’s Encrypt terms of service. That can be annoying for automation purposes in which case you can include the --agree-tos argument to avoid that text.

Postfix configuration

Config /etc/postfix/main.cf

Note: these lines disable SSLv3 support, see here for details. Should only affect really old clients.

SSL-stapling will make HTTPS requests a bit faster because the server will take care of retrieving the OCSP responses for the entire certificate chain and serve that to the clients. However, the first hit on your site right after restarting nginx will be slow because the server does need to download the OCSP chain once. That is also why you need the resolver to find the OCSP server that is stored in the certificate. Here I include Google’s public DNS, which should be just fine.

Prefixing server_name with a dot is a catch-all for the domain.tld and all its subdomains, unless those have their own server { } statement.

Check your installation

Now before you run off to some tools to check your setup, you should first visit the domain you are going to check at least once in your own browser. That will cause nginx to retrieve the OCSP responses and cache them. Otherwise the test will report that stapling is not working.

Changelog2017-11-16 – Cleaner modernized Postfix settings. These lines block all SSLv2 and SSLv3 connection and have a high impact on reducing incoming spam.2017-04-08 – Changed cert-only to certonly2016-08-21 – Full rewrite to use LetsEncrypt and HTTP/2