In a previous post I showed how to install NGINX in docker to act as a reverse proxy for Apache Guacamole. This is nice but it would be even nicer if the connection was encrypted.

Luckily getting an SSL certificate and setting it up for NGINX has be come easy and free a few years ago with the comming of Let’s Encrypt.

The easiest way would be to set up certbot (this will manage the request for the certificates) on the host machine, but the best way is to set it up inside a docker.

Prerequisites:

  • A working NGINX container
  • Ports 80 and 443 on the server are accessible from the outside world
  • You have a domain or subdomain configured to point to the server

First create a directory that will be accessible by the Certbot and NGINX. This directory is used by Let’s Encrypt to verify the server is under your control. The directory /docker/nginx/www is the web root for my NGINX Container.

1
2
3
4
cd /home/peter/docker/certbot #or whatever directory you use for docker volumes
mkdir log
mkdir lib
mkdir etc

Now spin a certbot container in staging mode (to prevent troubles if something is wrong with the configuration)

1
2
3
4
5
6
7
8
9
10
11
sudo docker run -it --rm \
-v /home/peter/docker/certbot/etc:/etc/letsencrypt \
-v /home/peter/docker/certbot/lib:/var/lib/letsencrypt \
-v /home/peter/docker/nginx/www:/data/letsencrypt \
-v "/home/peter/docker/certbot/log:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--register-unsafely-without-email --agree-tos \
--webroot-path=/data/letsencrypt \
--staging \
-d yourdomain.com

If everything goes well you can run the command for real now:

1
2
3
4
5
6
7
8
9
10
sudo docker run -it --rm \
-v /home/peter/docker/certbot/etc:/etc/letsencrypt \
-v /home/peter/docker/certbot/lib:/var/lib/letsencrypt \
-v /home/peter/docker/nginx/www:/data/letsencrypt \
-v "/home/peter/docker/certbot/log:/var/log/letsencrypt" \
certbot/certbot \
certonly --webroot \
--email youremail@domain.com --agree-tos --no-eff-email \
--webroot-path=/data/letsencrypt \
-d yourdomain.com

The location where the certificate is located is shown when the command finishes.
Remember that in the command above ‘/etc/letsencrypt’ is mapped to ‘/home/peter/docker/certbot/etc’. So we need to make sure we map it also for our NGINX docker.

Now we have a certificate and can configure NGINX to listen for https connections. Copy/paste the configuration block for port 80 and change the first lines to make NGINX listen on the right port and use the certificate.

1
2
3
4
5
6
    listen              443 ssl http2;
    server_name         yourdomain.com localhost;
        ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;

Make sure NGINX is started with the etc/letsencrypt directory mapped to theright directory on the docker host. Delete the extisting NGINX docker or creacte a new one with for example the command below.

1
2
3
4
5
6
7
sudo docker stop my-nginx
sudo docker rm my-nginx
sudo docker run --name my-nginx \
-v /home/peter/docker/certbot/etc:/etc/letsencrypt \
-v /home/peter/docker/nginx/www:/usr/share/nginx/html \
-v /home/peter/docker/nginx/conf/nginx.conf:/etc/nginx/conf.d/default.conf \
-p 80:80 -d --network="host" nginx

Verify that the secure connection is up and running. Change the server block for port 80 in the NGINX configuration as follows to redirect unsecure http traffic to https.

1
2
3
4
5
server {
    listen 80;
    server_name yourdomain.com localhost;
    return 301 https://$host$request_uri;
}

Now we can automate the renewal of the certificate.

1
sudo nano /etc/crontab

And add the following line:

1
0 23 * * * root docker run -it --rm -v /home/peter/docker/certbot/etc:/etc/letsencrypt -v /home/peter/docker/certbot/lib:/var/lib/letsencrypt -v /home/peter/docker/nginx/www:/data/letsencrypt -v "/home/peter/docker/certbot/log:/var/log/letsencrypt" certbot/certbot renew --webroot -w /data/letsencrypt --quiet && docker kill --signal=HUP my-nginx

Save the file and reload crondtab.

1
systemctl restart cron

That’s it!

Leave a Reply

Your email address will not be published. Required fields are marked *

Name *
Email *
Website

This site uses Akismet to reduce spam. Learn how your comment data is processed.