Overview

A common approach to setting up a new application or web service at Hatchet involves us provisioning a new SSL certificate on our own web server. You can use a CloudFlare certificate but there are a lot of times where a CloudFlare cert won’t suit your requirements due to the fact they use shared SSL certificates with unrelated sites and that you need to ensure there is no man in the middle that can impact performance security on your server or domain.

Avoiding Full Strict mode

When you use LetsEncrypt SSL CloudFlare DNS you can avoid Full Strict mode with CloudFlare, avoid having other unrelated sites on your certificate’s common name and make sure the encrypt certificate that is issued for your domain is fully controlled by yourself (private key and all)

Acme.sh to the rescue

Thankfully tools like acme.sh exist to make the process of issuing a dedicated ssl certificate on your own server very seamless. In this tutorial we will issue a universal ssl certificate on our server using the DNS API of acme.sh so that we can encrypt the communications between customers and our web application.

Avoiding the need for webroot

We won’t be exploring the webroot method here. Sometimes you may wish to enable HTTPS without having to make a change manually and without requiring full strict mode at CloudFlare. You may also be in a position where you have a firewall in front of your website keeping it secure, or a proxy that requires authentication in a browser or have a complex CDN setup.

AWS Global Accelerator

In some cases like ours, you might be using AWS Global Accelerator so have no need for CloudFlare which could result in much slower load times especially if you are on a free plan which uses least cost routing to CloudFlare.
The LetsEncrypt Approach

Lets Encrypt offer free SSL TLS certificates with no additional fees as well as Flexible SSL. Another bonus is there are no monthly fees, we don’t have to use other domain names, we can run this all from the command line on our own domain and we have full control over the SSL certificate that is generated. Any modern browser is compatible with this cert. To install Lets Encrypt on our website, follow the steps below.

Our Process

First up you’ll need to download and install the acme.sh software on your web server or VPS running the site you wish to protect with a Lets Encrypt SSL TLS certificate (to enable HTTPS). This can be done by running the command below

curl https://get.acme.sh | sh -s email=my@example.com 

acme.sh has changed to using ZeroSSL as the default CA as of August 1st 2021. While most SSL vendors are reputable, you may prefer the Lets Encrypt certificates like us as they’ve been around for quite some time now and I haven’t seen any major SSL issues with using their SSL certificates. Run the command below to switch over to Lets Encrypt as the default:

acme.sh --set-default-ca  --server  letsencrypt 

Now we need to pop over to CloudFlare and login to the CloudFlare dashboard. If you already have your domains or site configured within the CloudFlare DNS then make sure that you aren’t using the CloudFlare proxy with Flexible SSL or Full Strict mode for example as we want to ensure that CloudFlare doesn’t intercept our traffic and traffic will bypass CloudFlare proxy and go directly to our website. I’m not saying this isn’t a secure way to do things, I do trust CloudFlare a lot, I haven’t ready about any CloudFlare hijacks, however unlike CloudFlare I’m catering for a specific scenario here where my site is behind a firewall with a log, allowing access from particular IP addresses over HTTPS.

Once we’re signed into CloudFlare, we can head over to the ‘My Profile’ page and click on ‘API Tokens’. In this section we will create a new token. Use the template ‘Edit zone DNS’ as this will have some of the defaults we need.

Add permissions and make sure you have the following two permissions:

Zone -> DNS -> Edit 
Zone -> Zone -> Read 

For the ‘Zone Resources’ section, ensure that you lock down the API access to the specific zone that you wish to deploy the DNS change to for the issuing certificate. We don’t need our servers having access to all the other zones in our account if we can help it (we’re talking about HTTPS security here so we should follow some best practices).

Lock down the IP address if you can so that when we issue the new cert for our site, we know that the API request came from our platform directly.

Write down the API key and then head over to your Zone and record the CloudFlare Zone ID and CloudFlare Account ID as you’ll need these for the next step.

Head back over to your VPS (or instance) and punch in the following commands making sure to replace the variables and domain name with that for your particular site:

export CF_Token="yyyyyyyyyyyyyy"
export CF_Account_ID="xxxxxxxxxxxxx"
export CF_Zone_ID="xxxxxxxxxxxxx"
acme.sh --issue --dns dns_cf -d myapp.example.com

A log will appear showing what is happening while it connects to LetsEncrypt, grabs a token, then goes over to CloudFlare and provisions the corresponding record into the zone, validates and downloads the certificate.

At the end of the log you should see the list of certificate CA file, chain and private key. These you’ll need to make note of so that you can add these to your web servers configuration file. I’ve pasted below an example configuration that I use when deploying on nginx (we have disabled SSL by default)

ssl_session_cache shared:acme_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";
ssl_certificate /path/to/your/fullchain.cer
ssl_certificate_key /path/to/your/key.key