Lego – Automatic SSL Certificates and HTTPS for Everyone and Everywhere

Lego Logo

Lego is a Let’s Encrypt client written in Go, hence the name. It serves as an alternative to Let’s Encrypt’s own client certbot which can be found in many Linux distribution repositories to install. It is relatively simple to handle and manages SSL certificates just fine, as long as the domain is publically reachable, meaning you can reach it from anywhere by just putting it in your browser. So using certbot is usually fine and works for the occasion.

But what about domains that are not public? Like for your own local development? Usually, these domains look like wordpress.local for example and you won’t get SSL certificates for them. That is because they only exist in your local network and certbot can’t reach them for its DNS challenge. In other words, certbot can’t verify them and cannot create an SSL certificate for them.

Sure, you can try to trick certbot a bit by using a subdomain of your live domain for example and use certbot with the --certonly option. That works somehow, but the SSL certificate generated this way can’t be renewed automatically and you have to do this dance every 3 months. Pretty annoying, trust me, been there, done that.

Now wouldn’t it be nice if there is a way to get proper SSL certificates for your local domains as well and renew them automatically? Yes, it would, and there is! Lego to the rescue!

First off, some assumptions and preparations. This still will not work with a .local domain. You need a valid live domain, in my case ppfeufer.de. And this domain needs to be with a provider that is in Logo’s list of DNS Providers. Because what Lego does is, query your DNS provider and obtain the certificate for you.

So, let’s play this step by step on an example in my case. My local WordPress development is wp-local.ppfeufer.de and I like to have an SSL certificate for it. Why? Because I’d like to test if everything works with SSL, simple as that. Also, it’s 2022, no reason not to have SSL certificates, even for local domains :-P

Another assumption we have to make is that you are working on a Linux system. I have no idea how and even if this all will work on Windows at all. Sorry.

Install Lego

First, you need to install Lego. This can be done by simply cloning their GitHub repository and installing it from there.
Make sure you have Golang (>=1.17) installed as well, it’s needed, we’re installing a piece of software written in Go after all.

Clone the GitHub repository into a directory of your choice with:

git clone git@github.com:go-acme/lego.git

Now let’s change into the repository and compile the Lego client.

cd lego
export GO111MODULE=on
make build

This will take a while. This command pulls all the needed Go modules and compiled the Lego client, which can be found in the dist directory when done.

Now that the Lego client has been compiled, you’ll find it in the dist directory inside the git repository. Go ahead and make the file executable if it isn’t already (Seems to be depending on the distribution)

chmod +x lego

Making It Available on the System

After successfully compiling the Lego client, it needs to be made available to the command prompt. This means we have to move it somewhere where it can be executed by simply typing lego in our console. I for once have it in /usr/bin/, just a personal preference.

cd /usr/bin/
ln -s /path/to/the/legorepository/dist/lego .

As you can see, I’m not moving the file, I just link it. This has the advantage that when I update the Lego client, I don’t have to copy or move the file again. It’s linked and with that, it will always be the up-to-date version.

Usage

Now that the preparations are done, time to use the Lego client.

Pick your DNS provider from this list right here, the one I use in this example is Hetzner and as you can see, there is already an example given on how to obtain the SSL certificate.

Example:

cd /home/your_username

HETZNER_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
lego --email your@email.com --dns hetzner --domains your.domain.com run

Of course, you need an API key from Hetzner first, which you can create in your DNS console on Hetzner’s website. Make sure to never share this key with anyone!

Now you’ve got an SSL certificate which you can configure your web server with.

All you need to do is add an entry to your /etc/hosts file, to make sure your local machine doesn’t bother your ISP’s DNS server for the domain name and resolves it locally.

My example:

127.0.0.1    your.domain.com

From now on, every time your local machine queries this domain it resolves to its local address where your web server is listening.

Renew the Certificate

Let’s Encrypt SSL certificates are valid for 3 months, so it needs to be renewed regularly. For this it’s best to make use of a cron task.

Add the following to your crontab:

##
# Certbot for renewing SSL certificates
##
0 */6 * * * /home/your_username/.lego/renew-scripts/01_renew_certificates

As you can see, we make use of a shell script here. Change the file name to whatever you think is best.

The shell script we call with the cron task looks like this:

#!/usr/bin/env bash

# Load the Hetzner API key
export HETZNER_API_KEY_FILE=/home/your_username/.lego/hetzer-api-key

LEGO_ACCOUNT_EMAIL=your@email.com
LEGO_PATH="/home/your_username/.lego"
LEGO_CERTIFICATES_PATH="${LEGO_PATH}/certificates"
LEGO_RENEW_DAYS=10
LEGO_DNS_PROVIDER=hetzner

CERTIFICATE_RENEWED=False


for LEGO_CERTIFICATE_NAME in `/usr/bin/lego --path ${LEGO_PATH} list --names`
    do
        original=$(date -r "${LEGO_CERTIFICATES_PATH}/${LEGO_CERTIFICATE_NAME}.crt")

        /usr/bin/lego \
            --path ${LEGO_PATH} \
            --email ${LEGO_ACCOUNT_EMAIL} \
            --accept-tos \
            --dns ${LEGO_DNS_PROVIDER} \
            --domains ${LEGO_CERTIFICATE_NAME} \
            renew --days ${LEGO_RENEW_DAYS}

        actual=$(date -r "${LEGO_CERTIFICATES_PATH}/${LEGO_CERTIFICATE_NAME}.crt")

        if [ "${original}" != "${actual}" ]
            then
                CERTIFICATE_RENEWED=True
        fi
    done


if [ ${CERTIFICATE_RENEWED} == True ]
    then
        systemctl restart apache2.service
fi


exit $?

The script needs to be executable, so run:

chmod +x /home/your_username/.lego/renew-scripts/01_renew_certificates

Update the Lego Client

Updating the Lego client is pretty straightforward. All you need to do is pull the latest from GitHub and compile it again.

cd /path/to/the/legorepository/
git pull
export GO111MODULE=on
make build

That’s it.

Leave a Reply

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