Let’s Encrypt is a new Certificate Authority (CA) that provides an easy way to obtain and install free TLS/SSL certificates, thereby enabling encrypted HTTPS on web servers. It simplifies the process by providing a software client, Certbot, that attempts to automate most (if not all) of the required steps. Currently, the entire process of obtaining and installing a certificate is fully automated on both Apache and Nginx web servers.
In this tutorial, we will show you how to use Certbot to obtain a free SSL certificate and use it with Nginx on Ubuntu 14.04 LTS. We will also show you how to automatically renew your SSL certificate.
We will use the default Nginx configuration file in this tutorial instead of a separate server block file. We recommend creating new Nginx server block files for each domain because it helps to avoid some common mistakes and maintains the default files as a fallback configuration as intended. If you want to set up SSL using server blocks instead, you can follow this Nginx server blocks with Let’s Encrypt tutorial.
Before following this tutorial, you’ll need a few things.
sudo
privileges. You can learn how to set up such a user account by following our initial server setup for Ubuntu 14.04 tutorial.example.com
, that domain must resolve to your server for the validation process to work. Our setup will use example.com
and www.example.com
as the domain names, so both DNS records are required.Once you have all of the prerequisites out of the way, let’s move on to installing Certbot, the Let’s Encrypt client software.
The first step to using Let’s Encrypt to obtain an SSL certificate is to install the certbot
software on your server. The Certbot developers maintain their own Ubuntu software repository with up-to-date versions of the software. Because Certbot is in such active development it’s worth using this repository to install a newer Certbot than provided by Ubuntu.
First, add the repository:
- sudo add-apt-repository ppa:certbot/certbot
You’ll need to press ENTER
to accept. Afterwards, update the package list to pick up the new repository’s package information:
- sudo apt-get update
And finally, install Certbot with apt-get
:
- sudo apt-get install python-certbot-nginx
The certbot
Let’s Encrypt client is now ready to use.
Certbot can automatically configure SSL for Nginx, but it needs to be able to find the correct server
block in your config. It does this by looking for a server_name
directive that matches the domain you’re requesting a certificate for. If you’re starting out with a fresh Nginx install, you can update the default config file:
- sudo nano /etc/nginx/sites-available/default
Find the existing server_name
line:
server_name localhost;
Replace localhost
with your domain name:
server_name example.com www.example.com;
Save the file and quit your editor. Verify the syntax of your configuration edits with:
- sudo nginx -t
If that runs with no errors, reload Nginx to load the new configuration:
- sudo service nginx reload
Certbot will now be able to find the correct server
block and update it. Now we’ll update our firewall to allow HTTPS traffic.
Certbot provides a variety of ways to obtain SSL certificates, through various plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary:
- sudo certbot --nginx -d example.com -d www.example.com
This runs certbot
with the --nginx
plugin, using -d
to specify the names we’d like the certificate to be valid for.
If this is your first time running certbot
, you will be prompted to enter an email address and agree to the terms of service. After doing so, certbot
will communicate with the Let’s Encrypt server, then run a challenge to verify that you control the domain you’re requesting a certificate for.
If that’s successful, certbot
will ask how you’d like to configure your HTTPS settings:
OutputPlease choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
-------------------------------------------------------------------------------
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
-------------------------------------------------------------------------------
Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
Select your choice then hit ENTER
. The configuration will be updated, and Nginx will reload to pick up the new settings. certbot
will wrap up with a message telling you the process was successful and where your certificates are stored:
OutputIMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/example.com/fullchain.pem. Your cert will
expire on 2017-10-23. To obtain a new or tweaked version of this
certificate in the future, simply run certbot again with the
"certonly" option. To non-interactively renew *all* of your
certificates, run "certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Your certificates are now downloaded, installed, and configured. Try reloading your website using https://
and notice your browser’s security indicator. It should represent that the site is properly secured, usually with a green lock icon. If you test your server using the SSL Labs Server Test, it will get an A grade.
Let’s Encrypt’s certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. The certbot
package we installed takes care of this for us by running ‘certbot renew’ twice a day via a systemd timer. On non-systemd distributions this functionality is provided by a script placed in /etc/cron.d
. This task runs twice a day and will renew any certificate that’s within thirty days of expiration.
To test the renewal process, you can do a dry run with certbot
:
- sudo certbot renew --dry-run
If you see no errors, you’re all set. When necessary, Certbot will renew your certificates and reload Nginx to pick up the changes. If the automated renewal process ever fails, Let’s Encrypt will send a message to the email you specified, warning you when your certificate is about to expire.
In this tutorial we’ve installed the Let’s Encrypt client certbot
, downloaded SSL certificates for our domain, configured Nginx to use these certificates, and set up automatic certificate renewal. If you have further questions about using Certbot, their documentation is a good place to start.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Software Engineer @ DigitalOcean. Former Señor Technical Writer (I no longer update articles or respond to comments). Expertise in areas including Ubuntu, PostgreSQL, MySQL, and more.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Great article, and you were crazy-fast with the publication - a jiffy after the public beta is out. Kudos!
great job, i was looking for how to do it on nginx, set it up easy enough for an owncloud server running apache, this made it super easy to secure a reverse proxy i am running using nginx, which i prefer. thanks!
Line
netstat -na | 'grep :80.*LISTEN'
should be
netstat -na | grep ':80.*LISTEN'
Does port 80 have to be always open in order for this to work? I mean, what if I have some websites that are still http, so nginx would be listening to port 80 for them…
Do I have to set https for all my websites and make sure the the port 80 is not used by nginx ever, in order for this standalone plugin to work?
This is a great tutorial on lets encrypt with nginx. I have got pretty much everything working as expected. I’m not certain if it’s required but I made the ‘root’ directory as specified in the .ini file to be writeable by the user under which the web server runs. I will experiment further to see if this is really necessary.
A question :
The script that is run under cron to check for the renewal status of the certificates - does this need to be run as a user that can ‘sudo’ without a password ? I would have thought this to be the case but it is not mentioned here or in the tutorial for setting sudo up to which is referred. If so, would it be wise to limit the commands that can be run by this user to be just the renewal script and nothing else ?
Great article!
Small detail: you are downloading the le-renew-webroot script to /usr/local/sbin, but have /usr/sbin/le-renew-webroot in the crontab
Great article, thank you very much!
I’ve followed the steps to allow only the most secure SSL protocols and ciphers. However, Chromium says my web is encrypted with an obsolete ciphersuite (roughly, because I’m using the Spanish version). It uses AES-256-CBC, HMAC-SHA1 and ECDHE_RSA. Should it use HMAC-SHA256 instead? Why is this happening?
The ./letsencrypt-auto certonly --standalone
command seems to fail, telling me that the domain name contains invalid characters.
I believe this is supposed to be:
./letsencrypt-auto certonly --standalone -d example.com
i’m having errors, I believe it’s because my nginx configuration (from the one-click-app drupal install) blocks hidden directories. Could you perhaps add a block to the nginx configuration that allows the .well-known/acme-challenge directory
First of all, thank you for this very nice article! I used this on a Centos 7.2 box and it worked like a charm!
I ran into an ‘issue’, I got only a B at SSL labs using this configuration. I fixed it by generating a custom diffie hellman 2048 primes set as described on this page.
https://weakdh.org/sysadmin.html
Maybe you can update your guide with this, if you find it relevant.
Thanks, great article! It worked on my Debian 8 minimal installation, with only one little glitch: I had to install bc tool manually, in order to get the le-renew-webroot script to work.
Thanks for this great tutorial!
I’m sure that, with advanced bash scripting skills, it should be possible to adapt the le-renew-webroot script to handle multiple virtual hosts, but my bash skills are not what they should be.
In the meantime, will it be okay to create a script and a matching cli config file for each virtual host?
E.g.
/usr/local/sbin/le-renew-mywebsite.com
/usr/local/sbin/le-renew-anotherwebsite.org
...
with corresponding config files:
/usr/local/etc/le-renew-mywebsite.com.ini
/usr/local/etc/le-renew-anotherwebsite.org.ini
...
Thanks.
Great article, thanks !
I guess there is a little mistake here :
30 2 * * 1 /usr/sbin/le-renew-webroot >> /var/log/le-renewal.log
It should be
30 2 * * 1 /usr/local/sbin/le-renew-webroot >> /var/log/le-renewal.log
Mitchell,
Excellent write up! Can’t give you enough kudos for this article, great stuff : )
I have a nginx reverse-proxy listening to port 80 and 443 (with HTTPS enabled), it routes the traffic to another nginx web server sitting behind.
In this scenario, am I able to use the script to auto-renew certs? I would assume the answer is no
since the website has no port80 directly exposing to internet?
This is great - thank you very much! It helped me a lot… :)
You may want to add in ‘Nginx configuration additions — 3 of 3’ your domain with www before (to prevent errors in the renewal step):
server_name example.com www.example.com;
Also I had to install bc to make your script work:
sudo apt-get install bc
I need to publish both 80 and 443 ports in a docker container in order to successfuly build the certs. Is it missed in the tutorial (in verfy ports open section) or am I doing something wrong?
This comment has been deleted
Awesome tutorial. Exactly what I needed. Thanks!
If you are moving your server and domain name to new hardware, will it be sufficient to restore your /etc/letsencrypt dir from backup? Assuming the nginz configuration is the same. I’m thinking about how to migrate an existing setup. Specially an EC2 instance with elastic IP.
Thanks.
For the renewal script to execute correctly in my environment, I needed “bc” to be installed. For Ubuntu:
sudo apt-get install bc
Hi there, I’m getting an error when trying to follow Step 4. Here’s my terminal:
[redacted]:/opt/letsencrypt# ./letsencrypt-auto certonly -a webroot --agree-tos --renew-by-default --webroot-path=/usr/share/nginx/html -d ghostlyco.de -d www.ghostlyco.de
Updating letsencrypt and virtual environment dependencies......
Requesting root privileges to run with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly -a webroot --agree-tos --renew-by-default --webroot-path=/usr/share/nginx/html -d ghostlyco.de -d www.ghostlyco.de
Failed authorization procedure. www.ghostlyco.de (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.ghostlyco.de/.well-known/acme-challenge/[redacted] [45.55.95.134]: 404, ghostlyco.de (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://ghostlyco.de/.well-known/acme-challenge/[redacted] [45.55.95.134]: 404
IMPORTANT NOTES:
- The following 'urn:acme:error:unauthorized' errors were reported by
the server:
Domains: ghostlyco.de, www.ghostlyco.de
Error: The client lacks sufficient authorization
Not sure what’s causing that, any ideas?
EDIT: I suspect the webroot is incorrect, cding in to /usr/share/nginx/html and runing ls doesn’t appear to contain the files for my ghost installation. I used the single click installer for Ghost 0.7.4 on Ubuntu 14.04 LTS. Looking in to why the grep would be returning that path if that’s not the path used…
EDIT 2: Okay, I think the correct web root for me is /var/www/ghost, but putting that in the command throws the same error. Hmm.
@revxx14 See this comment above for a possible explanation of what you might be experiencing.
This comment has been deleted
Great tutorial. Here’s a few things that I learned during the process, hopefully to help others:
Thanks for the tutorial!
There’s a typo on the “well-known” location block. The path is currently written as /.well_known
(with an underscore), but it should be /.well-known
(with a dash).
Is it possible to revoke certs after playing around with letsencrypt ?! I want to delete all created certs and create new certs. thanks so far.
I’m not sure what the underlying issue is, but I found that I was getting 403 errors until I changed the location block for well-known
to:
location ~ /.well-known { allow all; }
Hope that helps someone (or at the very least the future me who comes back to look at this article!)
I’ve read through all the comments, but I keep getting the following error.
Failed authorization procedure. www.xxxxx.xxxxx (http-01): urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.xxxxx.xxxxx/.well-known/acme-challenge/5ZcvS9HmCGKTz8EzxNEvJPfgPNCBgTyjCS75RvWzTxU [xxx.xxx.xxx.xxx]: 404
I’ve added the necessary code (see below) to the server block and restarted nginx. I’ve checked that the .well-known folder is in my web root which is reflected in server block. Does anyone have any suggestions? I’m at a complete loss!
allow all;
}```
I just looked in the acme-challenge directory and I don't see any files. Is 5ZcvS9HmCGKTz8EzxNEvJPfgPNCBgTyjCS75RvWzTxU supposed to be in there per the error?
Really helpful! Question though, if say I’ve added a new sub domain, how do I add it in Let’s Encrypt? Note that all the previous sub domains shares the same cert.
One small problem I had, when I got to “How To Use the Webroot Plugin” the
./letsencrypt-auto certonly -a webroot --agree-tos --renew-by-default --webroot-path=/usr/share/nginx/html -d example.com -d www.example.com
did not want to execute.
Solved this problem was that we had setup a redirect from port 80 to 443 earlier, remove this and it will work if anyone else has this problem.
I’m using Drupal 7 with NGINX droplet. Our test/dev server all works well. However when I enable this on the live production site all of the http does indeed forward to https but when I try the login to the Drupal admin the page stays “stuck” and does not load the admin menu. Is there a directive/parameter that could be causing this?
Can a novice user to solve this problem? After; –standalon and ./letsencrypt-auto certonly
Failed authorization procedure. mydomain.com (tls-sni-01): urn:acme:error:tls : : The server experienced a TLS error during domain verification :: Failed to con nect to host for DVSNI challenge, www.mydomain.com (tls-sni-01): urn:acme:error :tls :: The server experienced a TLS error during domain verification :: Failed to connect to host for DVSNI challenge
IMPORTANT NOTES:
The following errors were reported by the server:
Domain: mydomain.com Type: urn:acme:error:tls Detail: Failed to connect to host for DVSNI challenge
Domain: www.mydomain.com Type: urn:acme:error:tls Detail: Failed to connect to host for DVSNI challenge
thanks!
I’m a bit of a novice especially with linux, can anyone help me solve me issue. After I run ./letsencrypt-auto certonly --standalone I get the following error: Deserialization error: The following field are required: uri,new_authzr_uri more of log here
Same thing with the webroot plugin.
I have tried searching but I cannot find anyone with similar issue.
Edit: I turns out after completely removing all letsencrypt folders (~/.local/share/letsencrypt, /var/lib/letsencrypt etc) etc and reinstallig it seems to be working correctly now. I think it broke because I didn’t have enough memory/swap when I originally installed
Thanks for the article If node js server with express is working in nginx Its mean that only nginx need to have this ssl procedure? I saw tuts where the https was done at node express side but nginx was not there.
This comment has been deleted
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.