updated 02 May, 2018 at 6:25 AM


How to secure a site with nginx and free letsencrypt ssl certificate

This tutorial will help you obtain a regular ssl certificate for one more domains that you specify in the server section of the nginx config file. If you want to obtain a wildcard certificate see this tutorial instead

I'll be using *example.com* as the domain name, don't forget to use your actual domain name!

Let's dive right into it!

Step 1 - Install nginx and certbot

I'll be using Ubuntu, if your OS is different please look up how to install nginx and certbot for your specific distribution.

First let's make sure that our system is updated:

$ sudo apt-get update && sudo apt-get upgrade

Install the package handling additional repository, most likely is already present but just in case is not.

$ sudo apt-get install software-properties-common

Add the certbot ppa repository:

$ sudo add-apt-repository ppa:certbot/certbot

Retrieve the list of available packages in the certbot repository.

$ sudo apt-get update

Finally, install certbot

$ sudo apt-get install python-certbot-nginx 

Step 2 - Configuring nginx

If you have a single site or ip based virtual hosts skip the next section. If you are using named based virtual hosts on the same ip make sure you read it carefully.

If are hosting named virtual hosts you need to make sure that your nginx version supports SNI (Server Name Indication) - an extension of the TLS protocol that requires the hostname to be sent at the beginning of the handshake.

SNI allows your server to select the right certificate for the host based on the name - which would be impossible when several named hosts share the same IP with standard TLS as it requires the handshake first (which in turn implies using the certificate) before the hostname is know. Note that even if the server supports it some old browsers and old mobile OS (like Android before 2.3) do not. Virtually all modern browsers and operating system support support SNI now.

If you want to be on the safe side use ip based virtual hosts, assuming that you have enough ip available on the server.


$ nginx -V
and look for TLS SNI support enabled

I will assume that there is a single site running on nginx using the default config file. If you are configuring a virtual hosts just edit the virtual host config file. All the other steps are the same.

Edit /etc/nginx/sites-enabled/default

Look for the server section and inside it for server_name. Replace it with your domain name (or names if you plan to use multiple hostname for the same site). This is how the config file looks for me:

server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;

        root /usr/share/nginx/html;
        index index.html index.htm;

        server_name example.com www.example.com;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
                # Uncomment to enable naxsi on this location
                # include /etc/nginx/naxsi.rules

Note that I'm using both example.com and www.example.com as I want the site to be available as https://example.com as well as https://www.example.com

Let's test the nginx configuration:

$ sudo service nginx configtest

If everything is ok you will get [OK] on the right bottom of your console. If not you will get [fail]. If it fails go back and double check the config file.

Let's restart nginx to use the new configuration:

$ sudo service nginx restart

Step 3 - Verify that you site can be reached

Open a browser and go to https://example.com

If you get a certificate error or certificate is not secure message you are good to go. That's expected as we didn't get our secure certificate yet. If you receive a host not found or host unreachable error double check that you set up properly your service - start with dns and then the firewall.

Step 4 - Getting our first certificate

Since we installed certbot for nginx let's leverage the fact that is capable of parsing our nginx config file and reconfigure it as needed:

$ sudo certbot --nginx

You will be asked a couple of questions, first for your email address. This email is used to communicate certificate related notifications, such as expire warning, renewal information and I assume (if needed) security news. Make sure that you use an email address that you monitor.

After that you will be asked if you accept the terms of service (mandatory) and if you want your email subscribed to EFF newsletters (optional).

Next you should be presented with the list of your host names you used to in the nginx config file and the option to select one or more (separated by comma) or to leave the field empty. Just leave the field empty and hit enter! This will use all your host names for the certificate (which is what we want).

Assuming that everything was done correctly so far you should have your first certficate!


Step 5 - Double checking automatic renewal

The letsencrypt certificate needs to be periodically renewed. By installing the certbot package we also installed a cron script that runs twice a day and checks if the certificate is about to expire - actually if is has less than 30 days until it expires - and starts the automatic renewal process.

Double check that the script does indeed exists at /etc/cron.d/certbot

To simulate the command executed by the cron daemon (just to make sure that everything is setup correctly, there are no errors, etc) run

$ sudo certbot renew --dry-run


As you can see the whole process is completely automated and very simple. The cornerstone is running

$ sudo certbot --nginx

after the nginx host was configured and certbox installed.

Be the first to comment!

Thank you for your comment.

Your message is currently under review because is triggered one of our spam filters.

We will let you know by email when the comment is approved.

leave a reply