Using Certbot HTTP-01 challenge using UPnP on a home router.

Chen Dar
2 min readNov 29, 2020

Letsencrypt is a nonprofit Certificate Authority that allows anyone to get a free TLS certificate. Certbot is a CLI utility used to get a certificate from Letsencrypt.
To get a certificate for a domain from Letsencrypt, you need to prove that you own the domain. This proof is achieved by answering a challenge. There are multiple types of challenges. We will use the HTTP-01 challenge.
In the HTTP-01 challenge, Certbot gets a token from Letsencrypt then runs an HTTP server on port 80. Letsencrypt service will try to reach http://<your-domain>/.well-known/acme-challenge/<TOKEN> to verify the domain. The problem is that port 80 is usually closed in your home network, and opening a port permanently to the internet is not secure.

We can reduce the risk by opening port 80 only when Certbot is requesting or renewing a certificate. This will be done with UPnP, a protocol that allows us to open and close ports dynamically in the router. Using Certbot pre and post hooks to issue a UPnP request to open and close port 80, our hook scripts:

Pre Hook

#!/usr/bin/env python3import miniupnpc
import os
u = miniupnpc.UPnP()
u.discoverdelay = 30
u.discover()
u.selectigd()
u.addportmapping(80, 'TCP', u.lanaddr, 80, 'acme', '')

Post Hook

#!/usr/bin/env python3import miniupnpc
import os
u = miniupnpc.UPnP()
u.discoverdelay = 30
u.discover()
u.selectigd()
u.deleteportmapping(80, 'TCP')

Now to running Certbot:

sudo certbot certonly -d <YOUR-DOMAIN> --standalone -n --pre-hook /home/darc/certbot/pre-hook.py --post-hook /home/darc/certbot/post-hook.py --agree-tos -m <YOUR-EMAIL>

The output will look similar to this:

Congratulations, now you have a shiny new certificate.

--

--