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.


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

git clone

Then run the installer:

./letsencrypt/letsencrypt-auto -h


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 =
# 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.


To generate a certificate, run something like:

letsencrypt-auto certonly -w /path/to/webroot -d -d

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/;
	ssl_certificate_key /etc/letsencrypt/live/;

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


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.

# -q quiet
# Default settings
today=$(date -d "now" +%s)
	#echo if we aren't being quiet
	if [ "$use_quiet" == false ]; then
		echo $1
# Parse arguments
while [[ $# > 0 ]]
case $key in
		# unknown option
shift # past argument or value
# Renewal
for d in `find /etc/letsencrypt/live/ -mindepth 1 -type d`; do
	domain=`basename $d`
	use_output "------------------------------"
	use_output "DOMAIN: ${domain}"
	use_output "------------------------------"
	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."
	#under the limit, let's renew!
	if [ "$days_expire" -lt "$limit" ]; then
		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)}')
		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)}')
		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."
			use_output "	Renewal succeeded."
	use_output ""
	#log it
	echo `date +"%F:%T"`" ${domain} ${days_expire} ${status}" >> /var/log/letsencrypt-renew.log
# Restart server?
if [ "$updated" == true ]; then
	service nginx restart >/dev/null 2>&1
	use_output "NGINX restarted"

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

Share Post