June 1, 2018 · Code Snippet DevOps Tutorial

Secure your website with Let's Encrypt and Nginx

The internet is becoming more and more insecure, and HTTPS connections might be a must for some projects, specially when dealing with sensitive user data.

Let's Encrypt allows the generation of free SSL/TLS certificates for HTTPS connections. Nginx is a reverse proxy software that can handle these certificates and secure the connection to your website or webservice from the user's browser.

Requirements

Securing your website/webservice

The procedure is relatively easy and simple. This example will assume Ubuntu Server as operating system, let's proceed.

Installing Let's Encrypt Certbot

We must first install the Let's Encrypt Certbot to generate the SSL/TLS certificates (and renew them):

sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install python-certbot-nginx

Installing Nginx

In case Nginx is not installed, proceed with this command:

sudo apt-get install nginx

Create the secure certificate

In this example we will assume a static website that will be exposed over www.mydomain.info and a web service over port 9000 to be exposed over service.mydomain.info (it is important to have configured A records in the DNS config environment that make @, www and service to our server IP).

Run the certbot to make the certificates:

sudo certbot --nginx -d mydomain.info -d www.mydomain.info -d service.mydomain.info

It is possible to add additional subdomains with the -d option. If certbot asks redirect HTTP traffic, choose No. The certbot will make the certificate now.

Configuring Nginx

Create a new .conf file for each website and webapp in your server inside /etc/nginx/sites-available/.

Static Website

Create first /etc/nginx/sites-available/website.conf and put in there:

#HTTP Server
server {  
    listen 80;
    server_name mydomain.info www.mydomain.info;
    return 301 https://mydomain.info$request_uri;
}

# HTTPS Server
server {  
    listen 443 ssl default_server;
    server_name mydomain.info;

    client_max_body_size 50M;

    location / {
        root /var/www/html;
    }

    ssl on;
    ssl_certificate /etc/letsencrypt/live/mydomain.info/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mydomain.info/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
    ssl_session_timeout 5m;
}

Remember to change mydomain.info for the name of your domain and /var/www/html in root for the location of your static site (your index.html, for example).

Webservice/Webapp

Create a /etc/nginx/sites-available/service.conf and put in there:

#HTTP Server
server {  
    listen 80;
    server_name mydomain.info www.mydomain.info;
    return 301 https://mydomain.info$request_uri;
}

# HTTPS Server
server {  
    listen 443 ssl default_server;
    server_name mydomain.info;

    client_max_body_size 50M;

    location / {
        proxy_pass http://localhost:9000;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
    }

    ssl on;
    ssl_certificate /etc/letsencrypt/live/mydomain.info/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mydomain.info/privkey.pem;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
    ssl_session_timeout 5m;
}

Remember to change mydomain.info for the name of your domain and http://localhost:9000 in proxy_pass for the port location of your webservice.

Test and enable Nginx configuration

Enable your site making a softlink to the Nginx enabled sites:

sudo ln -s /etc/nginx/sites-available/website.conf /etc/nginx/sites-enabled/website.conf
sudo ln -s /etc/nginx/sites-available/service.conf /etc/nginx/sites-enabled/service.conf

Now test your new configurations:

sudo nginx -t

If test passes, reload Nginx to make changes effective:

sudo service nginx restart

Configure firewall

Configure firewall to allow communication over ports 80 and 443. In case of using ufw, this two-liner can solve all:

sudo ufw allow 'Nginx Full'
sudo ufw reload

Wrapping up

This certbot will auto-renew your service periodically and automatically with a cronjob, ensuring that your site has secure certificates.

You can test the renewal process with:

sudo certbot renew --dry-run

Enjoy your secure server now. Cheers!