Deploying Let’s Encrypt certificates using tls-alpn-01 (https)

Some stock image to make this post more attractive (I hope 😜)

For those who don’t know what Let’s Encrypt is: it’s a service that lets you generate free certificates so you can run your website with https.

How does it work? You run the certbot tool from Let’s Encrypt on your Linux server, pick the domain name you want a certificate for, certbot verifies the domain is yours and generates the certificate for you. Let’s Encrypt provides you with 3 options to verify the domain is yours:

- Posting a specified file in a specified location on a web site (the HTTP-01 challenge)
- Offering a specified temporary certificate on a web site (the TLS-SNI-01 challenge)
- Posting a specified DNS record in the domain name system (the DNS-01 challenge)


As I was working on a server with only port 443 (https) open to the world, I had to use the tls-sni-01 challenge. However, since January 2018, Let’s Encrypt disabled tls-sni-01 as it could be used to request certificates for domains you don’t own.

That left me with http-01 and dns-01. As port 80 (http) was blocked and I didn’t have control over dns, I had to find another option.


After they abandoned tls-sni-01, work started on a new way to verify your domain using a https challenge: tls-alpn-01. This challenge works by creating specially crafted certificates just for the purpose of the verification. Also known als ALPN certificates.

As I was used to certbot, I thought I could just do this:

sudo certbot --preferred-challenges tls-alpn-01

Unfortunately, certbot responded with

None of the preferred challenges are supported by the selected plugin


At the time of writing tls-alpn-01 hasn’t been implemented in Let’s Encrypt’s certbot.

It turns out that this domain verification protocol is actually defined by ACME and that certbot is just an ACME client. In fact, next to certbot there are lots of other ACME clients you can use. You’ll find a list on the Let’s Encrypt website:

One of them is is an ACME client completely written in bash, so it works on Linux out-of-the-box. One of the latests commits is support for tls-alpn-01.

Request a certificate using tls-alpn-01 and

Start by getting the latest version of dehydrated:


Make sure you make./dehydrated executable:

chmod +x dehydrated

You will also need a config file and a domains.txt:


You’re domains.txt should contain a list with the domains you want a certificate for, for example:

(simply comment out everything else and add your domain)

The config file needs little editing:

  • CHALLENGETYPE: Specify tls-alpn-01.
  • ALPNCERTDIR: Set the location for your ALPN certificates (used by the verification process).
  • CERTDIR: Set your desired certification location. I chose to put them in a subfolder of nginx as I will be using nginx to serve my website.

You will also need an ALPN responder: a tiny https server that serves those ALPN certificates just for the verification process. You can copy-paste the example responder from the documentation: Name it

We’re not going to use a nginx load balancer as described in the documentation so make sure you change

HOST, PORT = "", 10443


HOST, PORT = "", 443

This way, the responder runs on port 443

Open a second terminal and run

sudo python3

You can check if the responder is running on port 443 with:

sudo netstat -tulpn | grep 443

Now for requesting your certificate using the tls-alpn-01 verification process, first run

./dehydrated --register --accept-terms

Then run dehydrated with the config file you edited earlier:

sudo mkdir /var/www/dehydrated
sudo ./dehydrated -c -f config

If all goes well, you should now have your certificates in “CERTDIR” you specified in the config file. In my case, that was /etc/nginx/certs.

Configure Nginx to use the certificates

As for configuring Nginx, create (or edit) a .conf file and add in your certificates:

server {
listen 443 ssl;
ssl_certificate /etc/nginx/certs/;
ssl_certificate_key /etc/nginx/certs/;

Make sure the fullchain.pem file and privkey.pem file match the ones in your /etch/nginx/certs/ folder. You might need to do some renaming.

Renewing certificates

If you want to renew your certificates, you will have to stop nginx with

sudo systemctl stop nginx

Start the responder with

sudo python3

In another terminal, request your new certificates with:

sudo ./dehydrated -c -f config

Kill your responder and restart nginx:

sudo systemctl start nginx

This might be a problem in production as you have to stop your nginx server temporarily. There should be a way to solve this by running a load balancer who then decides where to send the traffic to.


Hardware and software (reverse) engineer. Passionate about new technologies.