HTTPS and Encryption by Default

Encryption by default has become the new standard for web applications and many of the world’s top busiest sites have already made the switch to serving content via HTTPS. Google is no stranger to encryption, having made HTTPS the default for many of their apps long before it was cool, and just last year announcing the use of HTTPS as a rankings signal. Over the past few years, organizations like Facebook, Wikipedia, and the Federal CIO Council have shown that properly switching to HTTPS is no longer the performance hit it used to be, with many taking the next step by implementing HTTP Strict Transport Security (HSTS).

Barriers to HTTPS: Certificate Authorities

Until relatively recently, implementing HTTPS without subjecting users to browser warnings meant having to to pay a certificate authority (CA) to formally issue a certificate. With the cost of these certificates easily exceeding what many individuals would pay for domain registration and hosting, the likelihood of widespread adoption plummets. Lately SSL certificates have become much more affordable, and class 1 certificates could be obtained free of charge from StartCom provided you were willing to navigate their awkward interface and validation process.

Let’s Encrypt

Last year, the Electronic Frontier Foundation, Mozilla, Cisco, Akamai, and IdenTrust announced the formation of Let’s Encrypt, a new certificate authority created to remove the barriers preventing widespread adoption of HTTPS. They hope to simplify the entire certificate process and reduce setup time to 20-30 seconds through their Let’s Encrypt Client, a tool that uses the ACME (Automated Certificate Management Environment) protocol. I’ve been following their progress eagerly, and just last week I received an invitation to their closed beta, allowing me to finally issue trusted certificates for a handful of domains they whitelisted for me.

Let’s Encrypt SSL Certificates and Nginx
Client Installation

Based on my initial experience with the Let’s Encrypt Client, it seems there is still a lot of work to be done in order to achieve the goal of validating, issuing, and installing certificates in 30 seconds. The client works well for validating and issuing certificates once you understand the assumptions made. The Nginx installer is flagged as under development, and within the client you are warned that it does not work yet. If you have a non-standard Nginx configuration, you may end up with a jumbled mess by using the installer. Let’s Encrypt recommends cloning the client repository to get started. You’ll need to install git if you don’t have it already.

sudo apt-get update
sudo apt-get install git
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt





From here you can run letsencrypt-auto, a wrapper that handles OS-specific dependencies in a Python virtual environment. Rather than running the command with sudo, run it with your normal permissions. It will prompt you when it needs additional permissions. By default, the server is set to the staging/testing URL, but in this example I’m using production. Including auth causes the client to obtain the certificate but not install it.

Production Client

./letsencrypt-auto --agree-dev-preview --server \
    https://acme-v01.api.letsencrypt.org/directory auth

Using beta of letsencrypt-auto on Ubuntu.

Account Email


Account Email

The client then starts to install dependencies and set up the environment. If all goes well, you’re asked for an email address for notices and key recovery. There didn’t seem to be any email validation when I used it, but I’d suggest using a real address. I’m assuming they’ll add some sort of validation in the future to deter abuse.

Using beta of letsencrypt-auto on Ubuntu.

Terms of Service

Terms of Service

You’ll be prompted to review the Terms of Service. A link to the terms you’re agreeing to is added to your account metadata in /etc/letsencrypt/accounts/.

Using beta of letsencrypt-auto on Ubuntu.

Specify Domains

Specify Domains

Since we’re not using an installer, you’re prompted to enter the domains you’d like to use by hand separated by commas or spaces. Domains can also be specified from the command in with -d DOMAIN.

Automation isn’t there yet

Let’s Encrypt strongly recommends using the letsencrypt-auto method, but as of version 0.0.0.dev20151030 (on Ubuntu 14.04.3 with Nginx 1.8.0), it requires a bit of manual intervention. After specifying your domains, Let’s Encrypt attempts to authenticate by using listening on port 80 which is almost certainly in use.

The program nginx (process ID 1196) is already listening on TCP port 80. This will prevent us from binding to that port. Please stop the nginx program temporarily and then try again.

At least one of the (possibly) required ports is already taken.

I’m sure this could fixed by editing the client settings or choosing a particular authenticator. But after digging through the GitHub issues for a while, it doesn’t seem like the creators know what the “right way” should be. Since these certificates are only good for three months, and the automated renewal process isn’t quite there given that this is beta, stopping Nginx temporarily isn’t a big deal this time if it means getting certificates issued.

sudo service nginx stop
./letsencrypt-auto --agree-dev-preview --server \
    https://acme-v01.api.letsencrypt.org/directory auth

This time the certificate was successfully created and placed in /etc/nginx/live/example.com/

IMPORTANT NOTES:
– Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/rudeotter.com/fullchain.pem. Your cert
will expire on 2016-01-31. To obtain a new version of the
certificate in the future, simply run Let’s Encrypt again.

For now, the Nginx server blocks can just be configured manually. Go ahead and restart Nginx.

sudo service nginx start

Let’s Encrypt placed symlinks to the certificate, chains, and private key in /etc/letsencrypt/live/rudeotter.com — cert.pem chain.pem fullchain.pem privkey.pem. These can be plugged directly into Nginx configuration.

If you’re starting from scratch, Mozilla has a great SSL configuration generator. Here’s one using the Let’s Encrypt certificate.

server {
    listen 443 ssl spdy;
    listen [::]:443 ssl spdy;
    ssl_certificate /etc/letsencrypt/live/rudeotter.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/rudeotter.com/privkey.pem;;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # openssl dhparam -out dhparam.pem 2048
    ssl_dhparam /etc/nginx/dhparam.pem;

    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
    ssl_prefer_server_ciphers on;

    add_header Strict-Transport-Security max-age=15768000;

    ssl_stapling on;
    ssl_stapling_verify on;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    #ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
    ssl_trusted_certificate /etc/letsencrypt/live/rudeotter.com/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=86400;
    resolver_timeout 10;
 
    ....
}
%d bloggers like this: