Download as pdf or txt
Download as pdf or txt
You are on page 1of 38

How to Set Up Free SSL Certificates from Let's Encrypt

using Docker and Nginx


(https://www.humankode.com/ssl/how-to-set-up-free-
ssl-certificates-from-lets-encrypt-using-docker-and-
nginx)

The Complete Guide to Automating Certbot using Docker,


Nginx and Ubuntu on a Virtual Machine in the Cloud

Published on January 07, 2018


Docker (https://www.humankode.com/tag/docker), HTTPS
(https://www.humankode.com/tag/https), Let's Encrypt
(https://www.humankode.com/tag/lets-encrypt), Nginx
(https://www.humankode.com/tag/nginx), SSL
(https://www.humankode.com/tag/ssl), Ubuntu
(https://www.humankode.com/tag/ubuntu)
Updates:
19 June 2018: I updated the code and instructions to explain how
the certbot renewal process. Specifically, I explain how to use
certbot via a cron job to renew Let's Encrypt certificates and to
automatically reload the Nginx configuration and certificates.

---

I've been using Free SSL/TLS certificates from Let's Encrypt for
about 18 months. Recently, I started combining Docker with Let's
Encrypt. The tooling that Let's Encrypt's Certbot provides is
extensive, and the whole experience of using Docker with Let's
Encrypt is fantastic.

By combining Let's Encrypt with Docker, you get a fully automated


environment. SSL/TLS certificates are automatically renewed and
software running in Docker containers such as Nginx or the Let's
Encrypt Certbot agent are always kept up to date. You never have
to worry about updating software again or renewing SSL/TLS
certificates. It's quite clear why Docker and Let's Encrypt have
become so ubiquitous.

There's a convergence of different technologies that work together


in order to dockerize Let's Encrypt with Ubuntu and Nginx. The
reality is that it's quite simple to get up and running.

If you've been looking for an easy to read and follow guide that
will allow you to dockerize Let's Encrypt on Ubuntu, you've come
to the right place. Even if you're not interested in running Let's
Encrypt in Docker, this post will still show you how to obtain free
SSL/TLS certificates from Let's Encrypt as the certificate acquisition
steps are the same.

Youtube Tutorial
I created a Youtube tutorial that shows how to use Docker and Let's
Encrypt to issue free SSL certificates.
Set Up Free SSL Certi,cates from Let's Encrypt using Docker and Ngi…

Before we continue, let's look at what I'll be covering in this post:

How to install Docker on Ubuntu

How to set up and run Nginx in a Docker container

How to set up and run Certbot in a Docker container, and how


to get Certbot to issue an SSL/TLS certificate for a new domain

How to configure Nginx to use your SSL certificate

How to harden security in Nginx to get an A+ score on SSL


Labs

How to get an A rating on securityheaders.io


How to run a cronjob so that Certbot will automatically renew
your SSL/TLS certificate

I registered a new domain name, ohhaithere.com for the purposes


of this post and will be referring to that domain in all examples.

Running an Ubuntu Server 16.04 VM on AWS or


Azure
I'm not going to cover how to set up a virtual machine on AWS or
Azure, as that is a separate topic.

To get a VM up and running as a Web Server, at least for the


purposes of this post, you need to ensure the following:

You have a registered domain

You have set up a static public IP address for your server

You have pointed your Domain's A and CNAME records to the


server's public IP address

You have opened HTTP, HTTPS and SSH ports

You're running Ubuntu Server

Know how to SSH into your server


Install Docker on Ubuntu
SSH into your server and run the following commands to install
Docker on Ubuntu.

Add the GPG key and add the Docker repository from APT sources

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | s


udo apt-key add -

sudo add-apt-repository "deb [arch=amd64] https://download.


docker.com/linux/ubuntu $(lsb_release -cs) stable"

Update the Ubuntu package database

sudo apt-get update

And finally, install Docker

sudo apt-get install -y docker-ce

Install Docker Compose on Ubuntu


Docker Compose is used to orchestrate and run multiple containers
together.

Get the latest version of Docker Compose and install it

sudo curl -L https://github.com/docker/compose/releases/dow


nload/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/l
ocal/bin/docker-compose

Set execute permissions for Docker Compose

sudo chmod +x /usr/local/bin/docker-compose

As far as the server installation is concerned, that's really all there


is to it. Spinning up a new Ubuntu instance and installing docker
can literally be done in less than 5 minutes.

A Quick Overview of the Let's Encrypt Certificate


Issuance Process
Before I proceed, it's important to step back and understand how
the process works on a high level.

Let's Encrypt is an open, not for profit and free Certificate


Authority (CA). This means that they issue free SSL/TLS certificates.
In addition to this, they provide software that can issue the
certificates and renew certificates automatically. The software that
manages this process is called Certbot, and usually, you would
install this on your server.
The process for obtaining a free Let's Encrypt certificate is a 3-
part process:

1. Install Certbot on your server

2. Run Certbot with a command to obtain your SSL/TLS


certificate and save it on your server. The Certificate is valid
for 3 months and thus needs to be renewed every 3 months.

3. Set up a cron job (scheduler) to run Certbot with a Certbot


renew command on a weekly basis. When the cron job runs
and there are less than 30 days remaining until your
certificate expires, the certificate will renew.

How Certbot Works


Every time you run Certbot, whether it is the first time an SSL/TLS
certificate is issued or a certificate renewal, Certbot will perform
an ACME challenge request to validate that you are in control of
your domain. If the challenge request is successful, the Certbot
agent will install a new SSL/TLS certificate on your server.

This certificate consists of a private key and a public key and both
these keys are saved in a Let's Encrypt folder on your server. Your
web server, which is Nginx in this instance, loads both the private
and public keys in order to configure SSL/TLS for your site.

The public key is not secure and is sent to every browser that
makes a request to your site, while the private key is secure and is
not shared with clients. I will cover the certificate issuance process
in more detail in a subsequent post as it is an in-depth topic that
requires a separate post.

The key point with regards to the SSL/TLS certificate is that it


consists of 2 keys. Both keys are stored in a Let's Encrypt folder.
Your Nginx configuration file needs to reference both keys in order
to configure your site to use HTTPS.

A Better Solution: Run Let's Encypt's Certbot in a


Docker Container

The Certbot software gets updated with new releases often. If you
install Certbot on your server, this would involve uninstalling and
re-installing Certbot every time you need to update the Certbot
agent, which makes it a perfect candidate to run in a Docker
container. If Certbot is updated, a new image will automatically
be pulled from the Docker registry the next time the agent runs in
a docker container.
By dockerizing Certbot, the process for obtaining Let's Encrypt
certificates will now only consist of 2 parts:

1. To obtain the first Let's Encrypt SSL/TLS certificate, simply


execute a Docker run script. This script will look very
similar to the script that you would run natively on a server
through Certbot but instead is passed through Docker.
Docker will launch an instance of Certbot in a container and
run the script, and if the script is finished, the container will
close.

2. Set up a cron job that will execute another Docker run script
on a periodic basis. The script will look almost identical to
the one in the first step, give or take a parameter or two.

By running Certbot in a Docker container, we no longer need to be


concerned with maintaining the Certbot agent software. If a new
version is released, a new image will download and run the next
time the Docker container instance launches. Simple and
automated.

How to Dockerize Certbot


Before we can execute the Certbot command that installs a new
certificate, we need to run a very basic instance of Nginx so that
the domain ohhaithere.com is accessible over HTTP.

In order for Let's Encrypt to issue you a certificate, an ACME


Challenge Request is performed:

1. You issue a command to the Certbot agent

2. Certbot informs Let's Encrypt that you want an SSL/TLS


certificate

3. Let's Encrypt sends the Certbot agent a unique token

4. The Certbot agent places the token at an endpoint on your


domain that looks like http://ohhaithere.com/.well-
known/acme-challenge/{token}

5. If the token at the endpoint matches the token that was sent
to the Certbot agent from the Let's Encrypt CA, the challenge
request was successful and Let's Encrypt knows that you are
in control of the domain.
This basic instance of Nginx will only ever be run for the first time
that you request a certificate from Let's Encrypt. It's a basic
instance because it doesn't even need to have a default page. It just
needs to give write permissions to the Certbot agent so that it can
place a token at an endpoint for the challenge request and that's
all.

We can't configure a single instance of Nginx because the first


instance of Nginx will only be configured for HTTP since we do not
have an SSL/TLS certificate yet. Once we have the SSL/TLS
certificate, we can configure SSL/TLS on the full production version
of the site. If we then need to renew a certificate between 60 and
90 days after the first certificate was issued, the subsequent
challenge requests will be performed on the production version of
our site running on Nginx, and so we won't ever have to run the
basic instance of Nginx again.

To recap, the very first request for a Let's Encrypt certificate


will involve the following:

1. Configure a basic version of Nginx that only runs on HTTP


and gives the Certbot agent write access for the following
endpoint: http://ohhaithere.com/.well-known/acme-
challenge/{token}

2. Spin up the basic container of Nginx via Docker Compose

3. Execute a Docker run command that will spin up the Certbot


agent. The Certbot agent will perform the challenge request,
and if successful, place your SSL certificates in a Let's
Encrypt folder on your server.

4. Once the Certbot agent process is complete, the container


will automatically stop
5. Issue a Docker Compose down command which will stop
and close down your basic version of Nginx container

For all Let's Encrypt renewal requests, the process will involve
the following:

Ensure that your production version of Nginx is configured


and up and running. This container will be launched via
Docker Compose as soon as your site is ready to be deployed
and will stay up and running.

Configure a cron job that will execute a Docker run command


that performs a Certbot renew on a weekly or fortnightly
basis.

Set up Docker, Nginx and Certbot To Obtain Your


First Let's Encrypt SSL/TLS Certificate
On your server, create a new Directory:

sudo mkdir -p /docker/letsencrypt-docker-nginx/src/letsencr


ypt/letsencrypt-site

Then, create a new docker-compose.yml file

sudo nano /docker/letsencrypt-docker-nginx/src/letsencrypt/


docker-compose.yml

docker-compose.yml
version: '3.1'

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

The docker-compose.yml file does the following:

Pulls the latest version of Nginx from the Docker registry

Exposes port 80 on the container to port 80 on the host, which


means that requests to your domain on port 80 will be
forwarded to nginx running in the Docker container

Maps the nginx configuration file that we will create in the


next step to the configuration location in the Nginx container.
When the container starts, it will load our custom
configuration
Maps the /docker/letsencrypt-docker-
nginx/src/letsencrypt/letsencrypt-site location to the default
location of Nginx in the container. In this instance, it's not
really necessary, as the site only needs to be used for the
purposes of a challenge request, but it's always good to place a
default HTML file for troubleshooting purposes.

Creates a default Docker network

Then, create a configuration file for nginx

sudo nano /docker/letsencrypt-docker-nginx/src/letsencrypt/


nginx.conf

nginx.conf

server {
listen 80;
listen [::]:80;
server_name ohhaithere.com www.ohhaithere.com;

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

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

The nginx configuration file does the following:


Listens for requests on port 80 for URLs ohhaithere.com and
www.ohhaithere.com

Gives the Certbot agent access to ./well-known/acme-challenge

Sets the default root and file

Next, create an index.html file

sudo nano /docker/letsencrypt-docker-nginx/src/letsencrypt/


letsencrypt-site/index.html

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Let's Encrypt First Time Cert Issue Site</title>
</head>
<body>
<h1>Oh, hai there!</h1>
<p>
This is the temporary site that will only be used for the
certbot.
</p>
</body>
</html>
Before running the Certbot command, spin up a Nginx container in
Docker to ensure the temporary Nginx site is up and running

cd /docker/letsencrypt-docker-nginx/src/letsencrypt
sudo docker-compose up -d

Then, open up a browser and visit the domain to ensure that the
Docker container is up and running and accessible. As stated
earlier, it's not necessary to have a default index.html page for this
container, but it makes testing the container a lot easier, so I
always create one.

The Site Running in the Nginx Docker Container for Generating the First
Let's Encrypt Certificate
We're almost ready to execute the Certbot command. But before we
do, you need to be aware that Let's Encrypt has rate limits. Most
notably, there's a limit of 20 issued certificates per 7 days. So if you
exceeded 20 requests and are having a problem with generating
your certificate for whatever reason, you could run into trouble.
Therefore, it's always wise to run your commands with a --staging
parameter which will allow you to test if your commands will
execute properly before running the actual commands.

Run the staging command for issuing a new certificate:

sudo docker run -it --rm \


-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt
\
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsenc
rypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencryp
t" \
certbot/certbot \
certonly --webroot \
--register-unsafely-without-email --agree-tos \
--webroot-path=/data/letsencrypt \
--staging \
-d ohhaithere.com -d www.ohhaithere.com

After executing the above command, you should get the following
output which should indicate everything ran successfully.
Issue a new Let's Encrypt Certificate with Certbot and Docker in Staging
Mode

The command does the following:

Run docker in interactive mode so that the output is visible in


terminal

If the process is finished close, stop and remove the container

Map 4 volumes from the server to the Certbot Docker


Container:

The Let's Encrypt Folder where the certificates will be


saved
Lib folder

Map our html and other pages in our site folder to the
data folder that let's encrypt will use for challenges.

Map a logging path for possible troubleshooting if needed

For staging, we're not specifying an email address

We agree to terms of service

Specify the webroot path

Run as staging

Issue the certificate to be valid for the A record and the


CNAME record

You can also get some additional information about certificates for
your domain by running the Certbot certificates command:

sudo docker run --rm -it --name certbot \


-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt
\
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsenc
rypt-site:/data/letsencrypt \
certbot/certbot \
--staging \
certificates
Get Additional Information with the Certbot Certificates Command

If the staging command executed successfully, execute the


command to return a live certificate

First, clean up staging artifacts:

sudo rm -rf /docker-volumes/

And then request a production certificate: (note that it's a good


idea to supply your email address so that Let's Encrypt can send
expiry notifications)
sudo docker run -it --rm \
-v /docker-volumes/etc/letsencrypt:/etc/letsencrypt \
-v /docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt
\
-v /docker/letsencrypt-docker-nginx/src/letsencrypt/letsenc
rypt-site:/data/letsencrypt \
-v "/docker-volumes/var/log/letsencrypt:/var/log/letsencryp
t" \
certbot/certbot \
certonly --webroot \
--email youremail@domain.com --agree-tos --no-eff-email \
--webroot-path=/data/letsencrypt \
-d ohhaithere.com -d www.ohhaithere.com

If everything ran successfully, run a docker-compose down


command to stop the temporary Nginx site

cd /docker/letsencrypt-docker-nginx/src/letsencrypt

sudo docker-compose down

Set up Your Production Site to Run in a Nginx


Docker Container
Create the directories for our production site

sudo mkdir -p /docker/letsencrypt-docker-nginx/src/producti


on/production-site
sudo mkdir -p /docker/letsencrypt-docker-nginx/src/producti
on/dh-param

Let's start with the docker-compose.yml file

sudo nano /docker/letsencrypt-docker-nginx/src/production/d


ocker-compose.yml

docker-compose.yml
version: '3.1'

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
- ./production-site:/usr/share/nginx/html
- ./dh-param/dhparam-2048.pem:/etc/ssl/certs/dhparam-
2048.pem
- /docker-volumes/etc/letsencrypt/live/ohhaithere.com
/fullchain.pem:/etc/letsencrypt/live/ohhaithere.com/fullcha
in.pem
- /docker-volumes/etc/letsencrypt/live/ohhaithere.com
/privkey.pem:/etc/letsencrypt/live/ohhaithere.com/privkey.p
em
networks:
- docker-network

networks:
docker-network:
driver: bridge

The docker-compose does the following:

Allows ports 80 and 443


Maps the production Nginx configuration file into the
container

Maps the production site content into the container

Maps a 2048 bit Diffie–Hellman key exchange file into the


container

Maps the public and private keys into the container

Sets up a docker network

Next, create the Nginx configuration file for the production site

sudo nano /docker/letsencrypt-docker-nginx/src/production/p


roduction.conf

production.conf

server {
listen 80;
listen [::]:80;
server_name ohhaithere.com www.ohhaithere.com;

location / {
rewrite ^ https://$host$request_uri? permanent;
}

#for certbot challenges (renewal process)


location ~ /.well-known/acme-challenge {
allow all;
root /data/letsencrypt;
}
}

#https://ohhaithere.com
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ohhaithere.com;

server_tokens off;

ssl_certificate /etc/letsencrypt/live/ohhaithere.com/fu
llchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ohhaithere.co
m/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;
return 301 https://www.ohhaithere.com$request_uri;
}

#https://www.ohhaithere.com
server {
server_name www.ohhaithere.com;
listen 443 ssl http2;
listen [::]:443 ssl http2;

server_tokens off;

ssl on;

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 8.8.4.4;

ssl_certificate /etc/letsencrypt/live/ohhaithere.com/fu
llchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ohhaithere.co
m/privkey.pem;

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

Generate a 2048 bit DH Param file

sudo openssl dhparam -out /docker/letsencrypt-docker-nginx/


src/production/dh-param/dhparam-2048.pem 2048

Copy your site content into the mapped directory:

/docker/letsencrypt-docker-nginx/src/production/production-
site/

Spin up the production site in a Docker container:

cd /docker/letsencrypt-docker-nginx/src/production
sudo docker-compose up -d

If you open up a browser and point to http://www.ohhaithere.com,


you should see that the site loads correctly and will automatically
redirect to https://www.ohhaithere.com
The Production Website Running in an Nginx Docker Container with a Let's
Encrypt SSL/TLS Certificate

How to Renew Let's Encrypt SSL Certificates with


Certbot and Docker
Earlier, we placed the following section in the production Nginx
configuration file:
location ~ /.well-known/acme-challenge {
allow all;
root /usr/share/nginx/html;
}

The production site's docker-compose file then maps a volume into


the Nginx container that can be used for challenge requests:

production-nginx-container:
container_name: 'production-nginx-container'
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
#other mapped volumes...
#for certbot challenges
- /docker-volumes/data/letsencrypt:/data/letsencrypt
networks:
- docker-network

This effectively allows Certbot to perform a challenge request. It's


important to note that certbot challenge requests will be
performed using port 80 over HTTP, so ensure that you enable port
80 for your production site.

All that's left to do is to set up a cron job that will execute a certbot
command to renew Let's Encrypt SSL certificates.
Set Up a Cron Job to Automatically Renew Let's
Encrypt SSL/TLS Certificates
It's a good idea to run a daily cron job that attempts to renew Let's
Encrypt SSL certificates. It doesn't matter how many times this
command is executed as nothing will happen unless your
certificate is due for renewal.

To add a crontab, run the following commands:

sudo crontab -e

Place the following at the end of the file, then close and save it.

0 23 * * * docker run --rm -it --name certbot -v "/docker-v


olumes/etc/letsencrypt:/etc/letsencrypt" -v "/docker-volume
s/var/lib/letsencrypt:/var/lib/letsencrypt" -v "/docker-vol
umes/data/letsencrypt:/data/letsencrypt" -v "/docker-volume
s/var/log/letsencrypt:/var/log/letsencrypt" certbot/certbot
renew --webroot -w /data/letsencrypt --quiet && docker kil
l --signal=HUP production-nginx-container

The above command will run every night at 23:00. If the


certificates are due for renewal, the certificates will renew.
Additionally, the Nginx configuration and renewed certificates will
reload by executing the signal command at the end of the cron
command.
Get an A+ Score on SSL Labs
The configuration entered into the Nginx configuration file earlier
should ensure an A+ score on ssllabs.com. Go to ssllabs.com to
confirm.

Get an A+ Rating on SSLLabs

Hardening Your Site's Security and How to Get an


A rating on securityheaders.io
The last thing left to do is to harden the site's security and get an A
rating on securityheaders.io

production.conf

#https://www.ohhaithere.com
server {
# ....

location / {
#security headers
add_header Strict-Transport-Security "max-age=31536
000; includeSubDomains; preload";
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
#CSP
add_header Content-Security-Policy "frame-src 'self
'; default-src 'self'; script-src 'self' 'unsafe-inline' ht
tps://maxcdn.bootstrapcdn.com https://ajax.googleapis.com;
img-src 'self'; style-src 'self' https://maxcdn.bootstrapcd
n.com; font-src 'self' data: https://maxcdn.bootstrapcdn.co
m; form-action 'self'; upgrade-insecure-requests;" always;
add_header Referrer-Policy "strict-origin-when-cros
s-origin" always;
}

# ....
}
Get an A Score on securityheaders.io

View the Source Code on Github


You can get the source code
at https://github.com/thecarlo/letsencrypt-docker-nginx
(https://github.com/thecarlo/letsencrypt-docker-nginx)

Closing Thoughts
There's certainly no doubt that HTTPS adoption has reached a
tipping point (https://www.troyhunt.com/https-adoption-has-
reached-the-tipping-point/). Let's Encrypt has had a huge hand to
play in this by making free SSL/TLS certificates available to
everyone, while Google has been placing pressure on site owners
to adopt HTTPS. The newest versions of Google Chrome show sites
as insecure if they do not communicate over HTTPS.

There is, however, still a barrier to entry when it comes to


implementing free SSL/TLS certificates by Let's Encrypt. While
some hosting control panels and PaaS solutions in the cloud offer
UI solutions that make the process of obtaining Let's Encrypt
certificates effortless, it's certainly not an easy or straightforward
thing to do on a Virtual Machine. I spent quite some time reading
resources on the internet, but have never been able to find a
complete guide that not only explains how Let's Encrypt works, but
how to automate it with Docker and set it up in a secure way. I
found lots of scattered resources and ran into more problems than
I can recall. In the end, I was never able to find a proper guide and
had to resort to figuring it out on my own through trial, error and
persistence.

This is the guide that I wish was available when I started this
journey. It's my contribution towards lowering the barrier to entry
for HTTPS adoption. If there's any suggestions or improvements to
be made, which I'm sure there would be, let me know in the
comments and I will update accordingly.

Related Posts
Create a Self-Signed Certificate for Nginx in 5 Minutes
(https://www.humankode.com/ssl/create-a-selfsigned-certificate-
for-nginx-in-5-minutes)

Develop Locally with HTTPS, Self-Signed Certificates and ASP.NET


Core (https://www.humankode.com/asp-net-core/develop-locally-
with-https-self-signed-certificates-and-asp-net-core)

Resources
Certbot User Guide (https://certbot.eff.org/docs/using.html)

How to Install Docker on Ubuntu


(https://www.digitalocean.com/community/tutorials/how-to-install-
and-use-docker-on-ubuntu-16-04)

HTTPS adoption has reached the tipping point


(https://www.troyhunt.com/https-adoption-has-reached-the-tipping-
point/)

Let's Encrypt (https://letsencrypt.org/)

SecurityHeaders.io (https://securityheaders.io/)

SSL Labs (https://www.ssllabs.com/ssltest/)


more

Get in touch with me (/contact)

Twitter (https://twitter.com/thecarlo)

GitHub (https://www.github.com/thecarlo)

You might also like