Using letsencrypt with nginx on docker

Now that I have my site running on a docker container using nginx (more info here), I want to add a secure endpoint and support https. In order to do this, the first thing I would need is to have a SSL Certificate, but those are usually too expensive for a personal site. That were you can take advantage of letsencrypt.

letsencrypt nginx in docker Let’s Encrypt is a new Certificate Authority (CA) that provides an easy way to obtain and install free TLS/SSL certificates. It simplifies the process by providing a software client, letsencrypt, that attempts to automate most (if not all) of the required steps.

But, why do you need the certificate for? When you request a HTTPS connection to a webpage, the website will initially send its SSL certificate to your browser. This certificate contains the public key needed to begin the secure session. Based on this initial exchange, your browser and the website then initiate the SSL handshake. The SSL handshake involves the generation of shared secrets to establish a uniquely secure connection between yourself and the website.

The first thing you will need is to configure the access to the VM, which means that you will need to set up your DNS for each of the domains you plan to create the certificate for. In my case, I created two entries, one for nbellocam.me and the second one for www.nbellocam.me. In addition to setting up your DNS, you will need to make sure that the ports 80 and 443 are available and accessible. This requirements are due to the fact that the validation process will resolve your domain and access those ports to validate that you are how you say you are.

Then, you will need to download the letsencrypt client. To do this, you need to have git and bc and then execute the following command.

sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Once you have the client in your VM and you have access to it from your domain, the easiest way to obtain the certificate is to execute the following command, replacing the domains and your email.

sudo /opt/letsencrypt/letsencrypt-auto certonly --standalone --email [email protected] -d nbellocam.me -d www.nbellocam.me

This will create the certificate in your /etc/letsencrypt folder. Note that you have two folders there, archive and live. The first one contains all the certificates history while the second one contains a symlink to the latest one.

Now that you have the certificates its time to configure your docker-compose.yml file to enabling the 443 port as well as sharing the folders with the certificates.

web:
  restart: always
  build: ./conf/
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - /local/path/to/www:/usr/share/nginx/html
    - /etc/letsencrypt:/etc/letsencrypt
  external_links:
    - wordpress_web_1:bloghost

Before restarting the docker container using the new configuration, let’s update the nginx configuration file to add the support for https. To do this, update the server node for your site adding the following

server {
        listen 443 ssl;

        server_name	nbellocam.me www.nbellocam.me;

        ssl_certificate /etc/letsencrypt/live/nbellocam.me/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/nbellocam.me/privkey.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

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

        error_page  404              /404.html;
    }

You can then add a new node that permanent redirects all the content in port 80 that target your domains to the secure endpoint.

    server {
        listen 80;
        server_name nbellocam.me www.nbellocam.me;
        return 301 https://$host$request_uri;
    }

Finally, build the new image using docker-compose build and restart the container with docker-compose restart.

You should be able to connect to your https endpoint now. However, note that these certificate expires 90 days after the creation, so you’ll need to renew the certificate before it expires using the same command as before but this time adding the --renew-by-default parameter.

sudo /opt/letsencrypt/letsencrypt-auto certonly --standalone --renew-by-default --email [email protected] -d nbellocam.me -d www.nbellocam.me

Once everything is up and running, you can verify how secure its your site using this SSL Server test