Install "Let’s Encrypt" with NGINX and Phusion Passenger

castle and blue sky

We all need more SSL! But installing SSL certificates is a big PITA. Let’s Encrypt is a new certificate authority (CA) offering free and automated SSL/TLS certificates.

Certificates issued by Let’s Encrypt are trusted by most browsers in production today (including even some filthy ones like the Internet Explorer on Windows Vista).

Installing “Let’s Encrypt” is fairly easy:

bash$ apt-get update
$ apt-get install -y git
$ git clone /opt/letsencrypt
$ cd /opt/letsencrypt
$ ./letsencrypt-auto

Preparing for Domain Validation

“Let’s Encrypt” validates the domain by requesting a public file from your server. To add that file you need to adapt your nginx.conf:

bashserver {
  listen 80 default_server;

  location /.well-known/acme-challenge {
    root /home/9elements/letsencrypt;

and then restart your NGINX.

Generate the certificates

bashcd /opt/letsencrypt/
./letsencrypt-auto certonly -a webroot --webroot-path=/home/9elements/letsencrypt -d -d

this should output something like this:

bashChecking for new version...
Requesting root privileges to run letsencrypt...
/root/.local/share/letsencrypt/bin/letsencrypt certonly -a webroot --webroot-path=/home/9elements/letsencrypt -d -d

- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/ Your cert will
expire on 2016-07-13. To obtain a new version of the certificate in
the future, simply run Let's Encrypt again.
- If you like Let's Encrypt, please consider supporting our work by:

Donating to ISRG / Let's Encrypt:
Donating to EFF:

If it doesn’t try to put a file inside the “.well-known” directory and try to get.

bashmkdir /home/9elements/letsencrypt/.well-known/acme-challenge
$ echo "bar" > /home/9elements/letsencrypt/.well-known/acme-challenge/foo.txt
$ curl

Finally you should have the certificate and the corresponding private key in your /etc/letsencrypt/live/ directory.

Configuring NGINX to use the certificates

Now configure your NGINX server:

bashserver {
  listen 443 ssl;

  ssl_certificate /etc/letsencrypt/live/;
  ssl_certificate_key /etc/letsencrypt/live/;

and then restart your NGINX.


This command is OSX only but it helps to test various SSL diagnostics

nscurl --ats-diagnostics --verbose

All results should PASS.

Automatic renewal

Let’s Encrypt certificates are only valid for 90 days. This is why we create the following script in /opt/letsencrypt/ to renew them automatically and restart NGINX:


cd /opt/letsencrypt/
./letsencrypt-auto renew

if [ $? -ne 0 ]
ERRORLOG=`tail /var/log/letsencrypt/letsencrypt.log`
echo -e "The Let's Encrypt cert has not been renewed! \n \n" \
nginx -s reload

exit 0

Create /var/log/letsencrypt/ if it doesn’t exist. And run crontab -e to run the script every two month:

0 0 1 JAN,MAR,MAY,JUL,SEP,NOV * /opt/letsencrypt/

Final thoughts

Working with Let’s Encrypt was pretty straightforward. In the beginning we were afraid that it won’t work directly with Phusion Passenger (e.g. where to put the .well-known directory) but actually that part was a breeze. All we have to say is “Let’s Encrypt”…

One drop of bitterness: Wildcard certificates are currently not supported - but we’ll stay tuned.

PS: 9elements is a worldwide recognized software development consultancy. We work with techologies like React, Elixir and Ruby on Rails. If you like to play with new technologies: We’re hiring! If you just want to listen follow us on Twitter or like us on Facebook.

Cofounder of 9elements. Software alchemist since he was a kid. Knee deep in tech with building things in React, Rails or Solidity.