Let’s Encrypt

It’s not surprising something like the Let’s Encrypt service has come since the increased threat of someone spying on the traffic coming to and from your PC. I’ve been wanted to have a look into this for some time now but have lacked the time. At the time of writing this article I finally made the time so I thought I’d documented it while writing this article. Also the aim here is to use this blog as my test bed for using this service (which it is now running).

It’s not easy to get started with it

While Let’s Encrypt provides free certificates it’s not easy to get started with it. Now standard SSLs can be a bit overwhelming the first time you use them there is these days so much information on the web that it’s an easy Google search away to get it sorted. Plus most certificate providers have clear instructions on creating and signing them for most platforms.

Unlike conventional certificate signing you cannot just use openssl to generate a signing request and past this into a website. Let’s encrypt requires a client tool to initiate the request, the Let’s Encrypt servers then do a test on whether you are the valid owner of the domain and then send you the relevant information for the tool to create the certificate.

In this example I have used the letsencrypt.sh tool. On my FreeBSD servers this was a simple as pkg install letsencrypt.sh and should be straightforward to install on any *BSD or Linux distribution. Will have a look at Linux and include installation instructions when done.

The stumbling point I found in getting this going was the challenge part of the process. That is when you start a signing process the Let’s Encrypt servers will check whether you own the domain. It does this by either check the .TXT record within DNS or by testing whether it can check a specific URL from the web server behind the domain.

Using Let’s Encrypt

I decided the HTTP URL method would be the most straight forward method since it appears to be the default. This however proved initially to be a problem. I had no idea how to configure the URL. I’m actually very familiar with web servers (in this case Apache) however this appeared to be something you also had to configure on the letsencrypt.sh end.

The following is the first run of getting letsencrypt.sh running included the errors encountered and the solutions. I thought I’d run through the challenges I faced in case you hit them as well.

# letsencrypt.sh --cron --domain benhutton.com.au
#
# !! WARNING !! No main config file found, using default config!
#
+ Generating account key...
+ Registering account key with letsencrypt...

ERROR: WELLKNOWN directory doesn't exist, please create /usr/local/bin/.acme-challenges and set appropriate permissions.

Ok. To resolve this run “mkdir /usr/local/bin/.acme-challenges” and try again.

# letsencrypt.sh --cron --domain benhutton.com.au

#

# !! WARNING !! No main config file found, using default config!

#

Processing benhutton.com.au

 + Signing domains...

 + Creating new directory /usr/local/bin/certs/benhutton.com.au ...

 + Generating private key...

 + Generating signing request...

 + Requesting challenge for benhutton.com.au...

 + Responding to challenge for benhutton.com.au...

ERROR: Challenge is invalid! (returned: invalid) (result: {

  "type": "http-01",

  "status": "invalid",

  "error": {

    "type": "urn:acme:error:unauthorized",

    "detail": "Invalid response from https://benhutton.com.au/.well-known/acme-challenge/hyKpRy1drrC-QQH9Rg5Akpukd9wXOrgf355H6txPkOw: \"\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en-US\" prefix=\"og: http://ogp.me/ns#\"\u003e\n\u003chead\u003e\n\u003cmeta charset=\"UTF-8\"\u003e\n\u003cmeta name=\"viewport\" content=\"\"",

    "status": 403

  },

  "uri": "https://acme-v01.api.letsencrypt.org/acme/challenge/RAV36D-rIziiWJI6cRFS9APvSvVP85sutx4kNuIKh5U/179446581",

  "token": "hyKpRy1drrC-QQH9Rg5Akpukd9wXOrgf355H6txPkOw",

  "keyAuthorization": "hyKpRy1drrC-QQH9Rg5Akpukd9wXOrgf355H6txPkOw.EHURYiswcZG4uzUwds0mAwwPwyvBADsPWBmW72uPJGA",

  "validationRecord": [

    {

      "url": "https://benhutton.com.au/.well-known/acme-challenge/hyKpRy1drrC-QQH9Rg5Akpukd9wXOrgf355H6txPkOw",

      "hostname": "benhutton.com.au",

      "port": "80",

      "addressesResolved": [

        "104.27.175.62",

        "104.27.174.62"

      ],

      "addressUsed": "104.27.175.62"

    }

  ]

})

On the second attempt I got the above result. What this is telling me is that it is looking for the page “https://benhutton.com.au/.well-known/acme-challenge/hyKpRy1drrC-QQH9Rg5Akpukd9wXOrgf355H6txPkOw”.

Now for some more reading

After a bit of reading about this error and not being able to find the solution I decided to create this path. This proved fruitless as the actual file it’s trying to read (hyKpRy1drrC-QQH9Rg5Akpukd9wXOrgf355H6txPkOw) is dynamically created during the script run. After some more google searches and reading up on the letsencrypt.sh git page I found instruction on creating the alias for the Virtual Host.

To get the http verification working add something like the following in your apache virtual host.

Alias /.well-known/acme-challenge /var/www/letsencrypt

<Directory /var/www/letsencrypt>
        Options None
        AllowOverride None

        # Apache 2.x
        <IfModule !mod_authz_core.c>
                Order allow,deny
                Allow from all
        </IfModule>

        # Apache 2.4
        <IfModule mod_authz_core.c>
                Require all granted
        </IfModule>
</Directory>

Configuring letsencrypt.sh

The next step is to tell letsencrypt.sh about path in the virtual host. If you don’t it will not know where to create the file of the Let’s Encrypt service to find. On my machine the settings are in /usr/local/etc/letsencrypt.sh. Again on my machine it was populated with template config files. So what I had to do was make a copy of config.sh.example as in “cp config.sh.example config.sh”.

In this file you will find #WELLKNOWN=”${BASEDIR}/.acme-challenges”. This needs to be uncommented and changed to the path in your virtual host. In the above example that is /var/www/letsencrypt. On a *BSD system that is likely to be /usr/local/www/letsencrypt. As in:

WELLKNOWN="/usr/local/www/letsencrypt"

And now that this is been sorted out we can run the command again. This time with the shortened versions of the commands.

# letsencrypt.sh -c -d benhutton.com.au

# INFO: Using main config file /usr/local/etc/letsencrypt.sh/config.sh

+ Generating account key...

+ Registering account key with letsencrypt...

Processing benhutton.com.au

 + Signing domains...

 + Creating new directory /usr/local/etc/letsencrypt.sh/certs/benhutton.com.au ...

 + Generating private key...

 + Generating signing request...

 + Requesting challenge for benhutton.com.au...

 + Responding to challenge for benhutton.com.au...

 + Challenge is valid!

 + Requesting certificate...

 + Checking certificate...

 + Done!

 + Creating fullchain.pem...

 + Done!

And as you can see this time it was successful. As you can see in this case the certificate is found in “/usr/local/etc/letsencrypt.sh/certs/benhutton.com.au”. So all you need to do now is use the relevant to install the certificate on your website.

In additional to the certificate signing you will have to renew the certificate. Unlike commercial certificates you only get a small around of time before you need to renew. You can however do this automatically via a cron job.

Copyright © 2020 | Ben Hutton