Create TLS certificates for local networks

September 29, 2023

I am running various local apps on my home network, and I was annoyed for quite a while that I cannot run those services with HTTPS. Seeing warnings in browsers that my connection is not secure and not being able to have local network PWA’s were more than annoyance.

And none of the solutions looked feasible: Setting up custom self-signed certificates and installing them onto my devices is nothing more than Sisyphus’s daily woes. In the meantime, I would rather not expose my local network to the outside world and let the Pandora’s box open (trust me, this is my last reference to Greek mythology).

Until I came across a magical term: “DNS 01 Challenge” (https://letsencrypt.org/docs/challenge-types/#dns-01-challenge). No, this isn’t a Greek myth about the eternal fight with DNS caches and propagation issues. This is a way to validate that you own the domain that you want to create certificates for.

DNS-01 Challenge with certbot

I assume that you know what HTTPS and you have familiarity with Let’s Encrypt. certbot is simply the tool for managing certificates for Let’s Encrypt on a machine. And it offers a nifty functionality while creating a certificate with a preferred challenge method. When dns is the preferred method, the tool generates a key for us to set a DNS TXT record. And when we set that value, certbot validates the ownership of a domain and creates a wildcard certificate for the domain. How beautiful is that?

Let’s go over the steps one by one:

Running the certbot

Let’s execute the following command to start the process.

sudo certbot certonly --manual --preferred-challenges dns -d "*.DOMAIN"
# e.g:
sudo certbot certonly --manual --preferred-challenges dns -d "*.example.com"

certbot will ask us to set the DNS TXT record in our name registrar.

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.DOMAIN.

with the following value:

<REDACTED>

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.DOMAIN.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue 

Validating the DNS record

Before rushing and clicking ‘Enter’ to continue after setting the DNS record, let’s ensure that the record is set properly and propagated in the vastness of the DNS network.

In a separate terminal session, we can use dig to do that.

dig +short _acme-challenge.DOMAIN TXT
# e.g:
dig +short _acme-challenge.example.com TXT

If we can read the same key value we set previously in the terminal, congratulations, you can continue and tell certbot to create certificates now.

Using the certificate

If everything goes according to the plan (in the realm of computers, they rarely do), you should have 2 files: the certificate (a.k.a. fullchain.pem) and the private key (a.k.a. privkey.pem). Use those in your preferred reverse proxy application.

If you are using caddy for example, set up your Caddyfile as follows and don’t forget to fill up the <DOMAIN>, <FULLCHAIN_DIR>, <PRIVKEY_DIR> and <LOCAL_POST>.

https://<DOMAIN> {
  tls <FULLCHAIN_DIR>/fullchain.pem <PRIVKEY_DIR>/privkey.pem
  reverse_proxy localhost:<LOCAL_PORT>
}

Conclusion

Enjoy your secure connection and expand your local network kingdom as you wish. Please remember that the certificates do not live long. So feel free to set up an automation to create new ones periodically by using your registrar’s APIs, or just handle them manually.