Guillaume Hérail

Ramblings of a French guy

Lets Encrypt Behind The Firewall

Posted on — Apr 2, 2018

Dehydrated is a client for getting certificates from an ACME server (think let’s encrypt). Being written in bash, its dependencies are quite simple: curl/sed/grep/mktemp. Dehydrated allows us to write simple hooks that, in this post, we’ll use to do dns validation against our authoritative bind server. That way, you can use let’s encrypt certificates even if your server is behind a firewall! (provided it has access to your dns authoritative server)


For the rest of this post, we’ll assume that the hostname of the server we’re executing dehydrated on is and the hostname for which we want a certificate is

useradd -d /home/letsencrypt -m
apt update
apt install curl bind9utils
mkdir /home/letsencrypt/nskey
cd /home/letsencrypt/nskey
dnssec-keygen -a HMAC-MD5 -b 512 -n HOST -C

We have to install bind9utils to be able to generate our dnssec key, this key will then be used to push updates to specific dns records to our authoritative server.

Install dehydrated

su - letsencrypt
tar xvf master.tar.gz
mv dehydrated-master dehydrated
cp dehydrated/docs/examples/config .

Then edit config with your preferred editor and change the following:


Also, create a hook directory and then put the following in hook/

#!/usr/bin/env bash
set -e
set -u
set -o pipefail
NSUPDATE="nsupdate -k /home/letsencrypt/nskey/<.key FILE WE JUST GENERATED>"
case "$1" in
        ZONE=$(echo $2 | rev | cut -d'.' -f-2 | rev)
        printf "server %s\nzone %s.\nupdate add _acme-challenge.%s. %d in TXT \"%s\"\nshow\nsend\n" "${DNSSERVER}" "${ZONE}" "${2}" "${TTL}" "${4}" | $NSUPDATE
	sleep 30 # sleeping a bit to make sure changes have been propagated
        ZONE=$(echo $2 | rev | cut -d'.' -f-2 | rev)
        printf "server %s\nzone %s.\nupdate delete _acme-challenge.%s. %d in TXT \"%s\"\nsend\n" "${DNSSERVER}" "${ZONE}" "${2}" "${TTL}" "${4}" | $NSUPDATE
        # do nothing for now
        # do nothing for now
        echo Unknown hook "${*}"
        exit 1
exit 0
chmod +x hook/

Configure bind

Now that we have our key, we can tell bind to accept modifications from it. Edit /etc/bind/names.conf.local and add the following:

key "" {
	algorithm hmac-md5;
	secret "<CONTENT OF>"

Then find where your zone is configured (zone “domain.tld” {};) and add the following in it:

zone "" {
	grant name TXT;

And reload bind:

rndc reload


Now add the certificate you need in domains.txt:

echo "" > /home/letsencrypt/domains.txt

Tip: if you add multiple domains on the same line, then it’ll create a certificate with multiple subjectAltNames.

The first time you start dehydrated, it’ll ask for you to review and accept let’s encrypt TOS.

/home/letsencrypt/dehydrated/dehydrated -c -f /home/letsencrypt/dehydrated/config

Execute it a second time, if all goes well, you should get the following:

+ Creating fullchain.pem...
+ Done!

You can now find your certificates in /home/letsencrypt/certs/!

The -c option is meant to be executed regularly, it’ll renew certificates when needed. You can create a cronjob for that!