Let's Encrypt Nginx
Update [2017 Aug 5]: Certbot has been developed by EFF and others as an easy-to-use automatic client that fetches and deploys SSL/TLS certificates. I would recommend using it.
Why
Since you are here, you probably know what Let's Encrypt is and why it exists. If not, below is an executive summary (copied from here):
Anyone who has gone through the trouble of setting up a secure website knows what a hassle getting and maintaining a certificate can be. Let’s Encrypt automates away the pain and lets site operators turn on and manage HTTPS with simple commands.
No validation emails, no complicated configuration editing, no expired certificates breaking your website. And of course, because Let’s Encrypt provides certificates for free, no need to arrange payment.
At the time of writing, Nginx plugin is highly experimental, not included in letsencrypt-auto. So I didn't use it. This post documents how to upgrade your site from http to https and setup auto renewal. If your site is already using https and just want to setup auto renewal, you can skip to Auto Renew.
Prerequisites
- Nginx
- Debian-based distros, e.g. Ubuntu
- Git
- openssl
Setup Let's Encrypt
1. Install Let's Encrypt client
git clone https://github.com/letsencrypt/letsencrypt ~/letsencrypt
cd ~/letsencrypt
2. Free port 80 and 443
With the standalone plugin, Let's Encrypt need to use port 80 and 443 to issue a cert for you. So you need to make sure that port 80 and 443 are NOT in use.
Check if port 80 and 443 are used
netstat -na | grep ':80 .*LISTEN'
netstat -na | grep ':443 .*LISTEN'
If nothing shows up, you are good to go. Otherwise, you need to temporarily stop whatever process is using them.
3. Generate certificate
./letsencrypt-auto certonly --standalone
You will be prompted to enter email and domain. Just follow instructions.
After it's done, you should see something like:
Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/your.domain.com/fullchain.pem. Your cert
will expire on YYYY-MM-DD. To obtain a new version of the
certificate in the future, simply run Let's Encrypt again.
That means a cert has been issued to you. You can check it out in directory /etc/letsencrypt/live/your.domain.com
. It should have cert.pem
, chain.pem
, fullchain.pem
and privkey.pem
.
Now we need to config Nginx to use it.
4. Config Nginx
In the server block for https, you should have the following lines:
listen 443 ssl;
server_name your.domain.com;
ssl on;
ssl_certificate /etc/letsencrypt/live/your.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.domain.com/privkey.pem;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
4.1 Use strong DH group
For security reasons, I would strongly recommend using a strong DH group (Here is why).
To generate a strong DH group, 4096 bits
openssl dhparam -out /path/to/dhparams.pem 4096
It will take some time. After it's done, add this line in the same https server block
ssl_dhparam /path/to/dhparams.pem;
4.2 Use HTTP Strict Transport Security
I would also recommend to use HTTP Strict Transport Security. You just need to add this line in the https block
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
The complete Nginx config looks like
5. Reload Nginx
sudo nginx -s reload
6. Redirect Http to Https
This step is optional. But I think it's very useful. If you want to redirect your users who are still using http
to https
automatically, add the following http block
server {
listen 80;
server_name your.domain.com;
return 301 https://$host$request_uri;
}
If everything goes right, your site should be serving https now and http (if you did Step 6). Point your broser to https://your.domain.com
. And you should see a green lock on the location bar and you can see the certicate information. It looks like this
If you are a bit skeptical about the quality of your cert or your configuration, head over to SSL Labs to do a test. If you followed my recommendations to use a strong DH group and HTTP Strict Transport Security, your site should receive grade A+.
Auto Renew
By default, Let's Encrypt certs expire in 90 days. Right now, there is no built-in way to automatically renew it. But it's not hard to write a shell script and cronjob to do the job. You only need three steps
1. Create webroot config file
To renew, we need to use the webroot
plugin,
create /usr/local/etc/le-renew-webroot.ini
with the following content
rsa-key-size = 4096
email = youremail@example.com
domains = your.domain.com
authenticator = webroot
webroot-path = /usr/share/nginx/html
This file will be used a config file when running webroot
.
Btw, you should have root directive and /.well-known defined in the https server block. They are needed by webroot
for ACME chanllenge.
root /usr/share/nginx/html;
location ~ /.well-known {
allow all;
}
Then you can run this to get a new cert
./letsencrypt-auto certonly -a webroot --agree-tos --renew-by-default --config /usr/local/etc/le-renew-webroot.ini
2. Create renewal script
sudo curl -L -o /usr/local/sbin/le-renew-webroot https://gist.githubusercontent.com/thisismitch/e1b603165523df66d5cc/raw/fbffbf358e96110d5566f13677d9bd5f4f65794c/le-renew-webroot
sudo chmod +x /usr/local/sbin/le-renew-webroot
You probably want to take a look at the script /usr/local/sbin/le-renew-webroot
and customize it, especially le_path
and exp_limit
.
You can also run the script manually. If your cert is too new to renew, depending on your configuration in the script, you will see how many days are left. Otherwise, it will renew.
3. Cronjob
The last step is to create a cronjob to automatically run /usr/local/sbin/le-renew-webroot
. So that you can sleep well and not to worry that your cert expires.
sudo crontab -e
And add in
30 2 * * 6 /usr/local/sbin/le-renew-webroot >> /var/log/le-renewal.log 2>&1
This cronjob will attempt to renew Let's Encrypt at 2:30 AM every Saturday.
Summary
As you see, setting up Let's Encrypt and making it auto renew is not that hard. It used to be much more painful due to the cost of SSL cert and the efforts to create and maintain it, which gives many people (including myself) excuses not to use https. Now I can't find any excuse not to use https.
Let's Encrypt!