Viewing SSL View all News

How-To: Free SSL Certificates From Let’s Encrypt

SSL certificate costs have been steadily declining over the years. A decade ago, you’d have to shell out hundreds of dollars a year for a certificate, but more recently, adequate protection has been available from under $10.

Now, thanks to a non-profit initiative called Let’s Encrypt, SSL prices have truly bottomed out: free.

Let’s Encrypt operates a little different than traditional Certificate Authorities. Where historically certificate purchases have had to be authenticated through the domain’s registrant contact – a process that is all too often confusing for the client – Let’s Encrypt authenticates entirely through server-side software.

Let’s Encrypt is currently in beta, so there are still some kinks to work out, and a bit of elbow grease required for those wishing to give it a try. This article will help guide system admins through the setup process.

Installation

At the time of this posting, official distribution packages are mostly unavailable. So to get the source files, clone from git:

git clone https://github.com/letsencrypt/letsencrypt

Then run the installer:

./letsencrypt/letsencrypt-auto -h

Configuration

You can predefine settings in /etc/letsencrypt/cli.ini:

# This is an example of the kind of things you can do in a configuration file.
# All flags used by the client can be configured here. Run Let's Encrypt with
# "--help" to learn more about the available options.

# Use a 4096 bit RSA key instead of 2048
rsa-key-size = 4096

# Uncomment and update to register with the specified e-mail address
email = you@domain.com

# Uncomment to use a text interface instead of ncurses
text = True
agree-tos = True
renew-by-default = True

authenticator = webroot

Let’s Encrypt supports different authenticator methods for different server environments (e.g. Apache). We prefer “webroot”, which doesn’t mess with any server configuration files. This tutorial will assume you feel the same way.

Usage

To generate a certificate, run something like:

letsencrypt-auto certonly -w /path/to/webroot -d domain.com -d www.domain.com

This will generate a challenge directory at /path/to/webroot/.well-known. Your server will need to be configured to allow access to this hidden domain or the authentication will fail.

If all went well, you should now have a certificate! Certificates are stored in /etc/letsencrypt/archive/, but you’ll want to use the symlinks they generate in /etc/letsencrypt/live/ to ensure your host file is always pointing to the most recent version. An example nginx configuration looks like this:

server {
	...
	ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
	...
}

After restarting your web server, you should now have luxurious SSL encryption.

Renewal

For security reasons, Let’s Encrypt certificates are only valid for 90 days, so at this stage, you’ll want to get something in place to help automate the renewal process. At the time of this writing, there are no helpers to do this, so we wrote our own. The following script will test certificates found in the /etc/letsencrypt/live/ directory and renew any that are expiring within the next 25 days. If adapting this for your server, be sure and update the letsencrypt-auto binary path.

#!/bin/bash
#
# USAGE:
# -q quiet



#--------------------------------------------------
# Default settings

today=$(date -d "now" +%s)
limit=25
updated=false
use_quiet=false
use_output(){
	#echo if we aren't being quiet
	if [ "$use_quiet" == false ]; then
		echo $1
	fi
}



#--------------------------------------------------
# Parse arguments

while [[ $# > 0 ]]
do
key="$1"

case $key in
	-q)
	use_quiet=true
	;;
	*)
		# unknown option
	;;
esac
shift # past argument or value
done



#--------------------------------------------------
# Renewal

for d in `find /etc/letsencrypt/live/ -mindepth 1 -type d`; do

	domain=`basename $d`
	use_output "------------------------------"
	use_output "DOMAIN: ${domain}"
	use_output "------------------------------"

	cert="${d}/cert.pem"
	exp=$(date -d "`openssl x509 -in $cert -text -noout|grep "Not After"|cut -c 25-`" +%s)
	days_expire=$(echo \( $exp - $today \) / 86400 | bc)
	use_output "	Expiring in ${days_expire} days."
	status="ignored"

	#under the limit, let's renew!
	if [ "$days_expire" -lt "$limit" ]; then
		cert_file="/etc/letsencrypt/renewal/$domain.conf"

		use_output "	Starting renewal..."

		domains=$(grep --only-matching --perl-regex "(?<=domains \= ).*" "${cert_file}")
		# Determine last character
		last_char=$(use_output "${domains}" | awk '{print substr($0,length,1)}')
		# If last character is comma, then delete it from $domains
		if [ "${last_char}" = "," ]; then
			domains=$(use_output "${domains}" |awk '{print substr($0, 1, length-1)}')
		fi

		webroot=$(grep --only-matching --perl-regex "(?<=webroot_path \= ).*" "${cert_file}")
		# Determine last character
		last_char=$(use_output "${webroot}" | awk '{print substr($0,length,1)}')
		# If last character is comma, then delete it from $webroot
		if [ "${last_char}" = "," ]; then
			webroot=$(use_output "${webroot}" |awk '{print substr($0, 1, length-1)}')
		fi

		if ! /path/to/letsencrypt-auto certonly --renew-by-default --config /etc/letsencrypt/cli.ini -w "${webroot}" -d "${domains}" > /var/log/letsencrypt/renew.log 2>&1 ; then
			use_output "	Renewal failed."
			status="failed"
		else
			updated=true
			use_output "	Renewal succeeded."
			status="renewed"
		fi
	fi

	use_output ""

	#log it
	echo `date +"%F:%T"`" ${domain} ${days_expire} ${status}" >> /var/log/letsencrypt-renew.log

done;



#--------------------------------------------------
# Restart server?

if [ "$updated" == true ]; then
	service nginx restart >/dev/null 2>&1
	use_output "NGINX restarted"
fi

With the renewal process automated like this, we can simplify maintenance and make these free SSL certificates practical on production environments.

Be sure to check out our tips on How to Achieve an A+ SSL Configuration on Nginx to see how to maximize your encryption potential.

View all BBG Technology posts here.

Posted By
Josh Stoik

How To Achieve an A+ SSL Configuration on Nginx

Qualys SSL Labs has a wonderful tool to help evaluate your server’s SSL configuration. I recommend you take a moment to scan your site and see how you fare. Go do that now. I’ll wait. If you didn’t get a perfect score, you aren’t alone.

The default configurations for popular server-side software like OpenSSL often support cryptographically weak standards that can put users at risk. Even major corporations have room for improvement.

Keep your server secure

If you’re on a shared server or at the mercy of control panel software like cPanel or Plesk, unfortunately there isn’t anything you can do. But if you have root access and a little knowing of the command-line, this article will help you harden your configuration so you can get a perfect A+.

While the following examples are specific to Nginx, they should be able to help point any readers running Apache or Lighttpd servers in the right direction.

Obtaining a Certificate

First, let’s start with a quick refresher on how you go about getting a certificate in the first place. Make a directory outside your web root, and once in that directory, generate a private key and certificate signing request (CSR). Your key should be at least 2048 bytes. In this example we’ll generate one that is 4096 bytes. If you have an existing key and can’t remember how strong it is, you can type:

openssl rsa -in domain.com.key -text -noout | head -n 1

To generate a new key, use:

mkdir /var/www/domain.com/ssl
cd /var/www/domain.com/ssl
openssl req -new -newkey rsa:4096 -nodes -keyout domain.com.key -out domain.com.csr

The openssl command will quiz you about your domain and organization. The Common Name (CN) needs to be the fully-qualified-domain-name for which you are purchasing the certificate. Remember, domain.com and www.domain.com are technically two different domains, so enter the CN exactly as visitors are expected to reach it. Some certificates, such as Comodo’s PositiveSSL, are magically valid for both www and non-www variants (aren’t they sweet?).

You should now find two files in your ssl directory: domain.com.key and domain.com.csr. That key is meant to be private, so take a moment to update its permissions. If 600 is too restrictive for your environment, 640 might do the trick.

chmod 0600 domain.com.key

Now go buy a certificate. Namecheap offers decent Comodo certificates from as low as $9, or you could spend more money elsewhere. It doesn’t much matter. As part of the certificate activation process, you’ll be asked for the CSR you just created, so keep that handy. Different Certificate Authorities (CA) have different validation processes, so just follow whatever instructions you’re given.

Once your certificate has been issued, upload them to the directory containing your key and CSR. If you are issued two or more bundled certificates (which is a common practice), they must be stitched together into a single file for Nginx. The order is important, so double-check the CA’s documentation. For Comodo PositiveSSL certificates, run the following:

cat domain.com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > domain.com.combined.crt

Nginx Set Up

By default, OpenSSL uses a weak 1024 byte key for Diffie Hellman key exchanges.  Let’s bump this up to 4096 by running the following command.  It can take a while to complete, so go make a sandwich:

openssl dhparam -out /etc/nginx/dhparams.pem 4096

Now let’s make Nginx’s SSL configuration a little more secure by adding the following code to the http{} block of your /etc/nginx/nginx.conf file:

http {
	...

	##
	# SSL Settings
	##

	## force modern protocols and ciphers
	## and enable ssl cache for a small
	## performance boost

	ssl_prefer_server_ciphers On;
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
	ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
	ssl_session_cache shared:ssl_session_cache:10m;
	ssl_dhparam /etc/nginx/dhparams.pem;

	...
}

Now that we have the general out of the way, let’s move onto site-specific configurations. Open the configuration file corresponding to your site, something like /etc/nginx/sites-enabled/domain.com.conf.

Let’s start by adding a server block to redirect www.domain.com to domain.com, and also force HTTPS connections for everything. If www.domain.com is your main domain, simply reverse the www and non-www in the following examples.

server {
	listen 80;
	listen [::]:80 ipv6only=on;

	server_name www.domain.com domain.com;

	rewrite ^(.*) https://domain.com$1 permanent;
}

Now in your main server block for the domain, add the following:

server {
	listen 443 ssl;
	listen [::]:443 ssl ipv6only=on;

	server_name domain.com www.domain.com;

	#point to the combined certificate and key we generated earlier.
	ssl_certificate /home/domain.com/ssl/domain.com.combined.crt;
	ssl_certificate_key /home/domain.com/ssl/domain.com.key;

	#enable HSTS (in supported browsers) to make sure all subsequent
	#user requests are done over HTTPS regardless of protocol typed.
	add_header Strict-Transport-Security "max-age=31536000";

	#redirect non-canonical domain over SSL.
	#this will only work if your SSL certificate also covers www.domain.com.
	if ($host = 'www.domain.com' ) {
		rewrite ^(.*)$ https://domain.com$1 permanent;
	}
	...
}

If your server is not configured for IPv6, remove the second listen lines from the above examples. Speaking of IPv6, Nginx only wants to see a single ipv6only=on attribute per port across all your server blocks. If you have additional server blocks defined, simply omit that string from their definitions.

That’s it! Restart Nginx to apply the changes:

service nginx restart

Last Thoughts

You should now have pretty darn good SSL support! But the fun doesn’t end here!

New threats or vulnerabilities can pop up any time, to say nothing of the inevitable march of progress (advances in technology will eventually make your once great setup laughably inadequate).  Make sure you regularly apply any security patches made available to your distribution.  You should also periodically rerun the Qualys SSL Labs scan to see if any tweaks are needed to stay on top.

Posted By
Josh Stoik