LetsEncrypt TLS

CA Certificate

The request and configuration of the CA certificate can be done in two phases. The first step is to request the certificate form ‘Let’s Encrypt‘ and the second phase is to configure the web server ( or reverse proxy) to use the issued certificate.

Request Certificate

To request a certificate we will need the following:

  • Web sever that handles web requests from ‘Let’s Encrypt
  • Handle the ‘/.well-known/acme-challenge’

We will be using ‘Let’s Encrypt‘ provided tool known as ‘Certbot’ to initiate a CA Certificate request. This tool exists as a Docker container which we will use in our example. Before initiating the certificate request, we will setup the needed files.

Image showing the '<em>letsencrypt</em>' directory and '<em>letsencrypt-site</em>' sub directory.

docker-compose.yml file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
version: '1.0'
services:

letsencrypt-nginx-container:
container_name: 'letsencrypt-nginx-container'
image: nginx:latest
ports:
- "80:80"

volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./letsencrypt-site:/usr/share/nginx/html
networks:
- docker-network

networks:
docker-network:
driver: bridge

nginx.config file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
listen [::]:80;
server_name planningtasks.com www.planningtasks.com;

location ~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}

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

index.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Let's Encrypt Landing Page</title>
</head>
<body>
<h1>Cert Landing Page</h1>
</body>
</html>

Once you have all the files setup, run the following command to start an Nginx Docker instance. This will create a web server configured to handle the ‘Let’s Encrypt‘ certificate challenge. Check that the site is up using curl command.

1
$ docker-compose up -d

After the Nginx web server is up, use Docker Certbot to initiate a CA domain certificate challenge. The Certificate files generated as part of the challange will be located in the ‘docker-volumes/etc/…’  directory.

Remove –staging option when ready to request the production certificates.

1
2
3
4
5
6
7
8
9
10
11
12
$ docker run -it --rm \
-v /docker-volumes/etc/planningtasks:/etc/letsencrypt \
-v /docker-volumes/var/lib/planningtasks:/var/lib/letsencrypt \
-v /docker-volumes/var/log/planningtasks:/var/log/letsencrypt \
-v /...path_to.../letsencrypt-site:/data/letsencrypt \
certbot/certbot \
certonly --webroot \
--register-unsafely-without-email --agree-tos \
--webroot-path=/data/letsencrypt \
--staging \
-d planningtasks.com -d admin.planningtasks.com

Example of running the CA Certificate request using Certbot.

Check Certificates

Verify the certificates by using the following command, if valid, you should see the relevant certificate details:

1
2
3
4
5
6
7
$ docker run --rm -it --name certbot \
-v /docker-volumes/etc/planningtasks:/etc/letsencrypt \
-v /docker-volumes/var/lib/planningtasks:/var/lib/letsencrypt \
certbot/certbot \
--staging \
certificates

Example of validating certificates for planningtasks.com

Configure NGINX

At this point, the docker created in the “Request Certificate” phase is no longer needed and should be cleaned up. The certificates that are generated is what you want to retain.

Generate DH Param (optional)

This is optional and server to enhance the security of the web server. Note that if this step is skipped, subsequent scripts below might need to be adjusted. To generate the (.pem) file, use ‘openssl’ and the below command.

1
$ openssl dhparam -out /...path_to.../production/dh-param/dhparam-2048.pem 2048

The command generates a ‘dhparam-2048.pem’ file in the ‘dh-param’ directory.

.pem file generated using openssl.

Configure Nginx to use the certificate by adding configurations to the web server settings. In this example, we will be configuring Nginx as a reverse proxy web server.

Example Nginx configuration for a production site

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
upstream planningtasks {
server localbox:5000;
server localbox:5001;
}
server{
listen 80;
server_name planningtasks.com;
# Useful for a certificate renew challange by Certbot
location ~ /.well-known/acme-challenge {
allow all;
root /data/planningtasks;
}
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name planningtasks.com;
server_tokens off;

ssl_certificate /etc/planningtasks/live/planningtasks.com/fullchain.pem;
ssl_certificate_key /etc/planningtasks/live/planningtasks.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;

location / {
proxy_pass http://planningtasks;
#proxy_set_header X-Forwarded-For $remote_addr;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto https;
}
}

Before starting up a Docker Nginx instance using the below command, prepare the following files in the relative location. Note the location for the ‘production.conf’ and the ‘dhparam-2048.pem’ files.

docker-compose.yml file, xxx.xx.xxx.xxx points to the docker host IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: '1.0'

services:

production-nginx-container:
container_name: 'production-nginx-container'
image: nginx:latest
ports:
- 80:80
- 443:443
volumes:
- ./production.conf:/etc/nginx/conf.d/default.conf
- ./dh-param/dhparam-2048.pem:/etc/ssl/certs/dhparam-2048.pem
- /docker-volumes/etc/planningtasks/live/mycloudology.com/fullchain.pem:/etc/planningtasks/live/mycloudology.com/fullchain.pem
- /docker-volumes/etc/planningtasks/live/mycloudology.com/privkey.pem:/etc/planningtasks/live/mycloudology.com/privkey.pem
- /docker-volumes/data/planningtasks:/data/planningtasks
networks:
- docker-network
extra_hosts:
- "localbox:xxx.xx.xxx.xxx"

networks:
docker-network:
driver: bridge

For more details on how to find out the Docker host IP:
Customizing Nginx Docker container

Renew Certificate

Invoke Certbot to renew certificate that are referenced in the ‘/docker-volumes/data/planningtasks’ location.

1
2
3
4
5
6
7
# renew certbot cert
$ docker run --rm -it --name certbot \
-v "/docker-volumes/etc/planningtasks:/etc/letsencrypt" \
-v "/docker-volumes/var/lib/planningtasks:/var/lib/letsencrypt" \
-v "/docker-volumes/data/planningtasks:/data/letsencrypt" \
-v "/docker-volumes/var/log/planningtasks:/var/log/letsencrypt" \
certbot/certbot renew --webroot -w /data/letsencrypt --quiet

Restarting Nginx Docker:

1
2
3
4
5
6
7
$ docker kill --signal=HUP production-nginx-container

# Check for renewal errors in the logs
$ cat /docker-volumes/var/log/planningtasks/letsencrypt.log

# Check that date on the files has been renewed by Certbot
$ ls -l /docker-volumes/etc/planningtasks/renewal

For more articles that cover Let’s Encrypt: Install NGINX and configure TLS

source - Lets Encrypt container
source - Reverse proxy Nginx