I’m hosting my own mailserver to receive mail for the domains i own. My personal mail is running somewhere else. It’s the last public server i’m operating out there for my own purposes and it’s more for training purposes. Most of the ports of this server are hidden: By my own firewall on the server but by the firewall of the provider as well. It’s relatively low maintainance and so far i was too lazy to migrate everything to a different server giving the task of managing the mailserver away. I did automate most of the tasks managing the system. Except one.

The only non-automated task and the one that was really annoying to me was the renewal of the certificates for TLS. I’m using Let’s encrypt to obtain tthe certificates. So it’s a task i have to do every 90 days.

BTW: Soon they will offer certificates only valid for a few days and i think i will use them. In this light, no automation is not an option.

There are two ways to confirm that you are in control of the domain you want to get the certificate:

  • Proof of having control of the DNS configuration by adding a TXT record with a challenge
  • or putting a file in a directory on your webserver and let’s encrypt checks for this file.

But my mailserver had just a webserver for admin interfaces and so there was no need to have a public webserver. What you can’t reach is less probable to be an attack vector. This is the reason why i used firewall rules to block public access to the webserver and different means to access port 80/443 on the mailserver (it was really easy when i had a fixed ip but my current ISP don’t offer this for consumers).

So the servers of Let’s encrypt couldn’t reach a webserver on my mailserver to validate the domain ownership when requesting a certificate. I have chosen the TXT record as proof of control as it didn’t need any service on the server. However … most GUIs of domain name servers are a major pain and don’t have a decent way to automate stuff. For quite some time i did this renewal process manually every 90 days. And more than once i forgot to do this.

Until i had enough of this. I was frustrated about my laziness to fix this. I really thought about getting an additional domain at a service supporting the automated mechanisms of Let’s encrypt to insert the TXT record automatically. To my excuse: My job and another hobby i acquired 2 years ago took a lot of brain cycles.

But i still didn’t want to make the webserver on the system public accessible, not even a short time. My logfiles would be gargantuan already without rotating because of all the attempt to brute force passwords on the mailserver and even more so without fail2ban doing its job. So i have no hopes this would be an good idea to keep it open. It just looked prudent to have no public port 80/443 there. Would be another source of log entries. I just don’t want to wade through another long logfile. I know there are tools for this but this would be yet another tool i have to maintain.

However two things occured to me: “I’m the only person using this webserver” and “I just need the Let’s Encrypt stuff for a few seconds every 60 days”. Perhaps i could solve this with a horrible hack.

What the process is doing

  • Shutdown your webserver
  • Open up the firewall on port 80
  • Renew the certificate in standalone mode (so certbot is using its own webserver)
  • Close the firewall on port 80
  • Restart your webserver

It’s quite easy to setup:

# certbot certonly  --standalone --pre-hook "perl -e 'sleep int(rand(3600))'; systemctl stop apache2; ufw allow http" --post-hook "ufw deny http; systemctl start apache2" -d example.com

From now on the automatic processes will do their job as indicated by the output of the command

Certbot has set up a scheduled task to automatically renew this certificate in the background.

In /etc/letsencrypt/renewal/example.com.conf you will find the pre-hook and post-hook lines with the commands you have specified by command line options before.

pre_hook = perl -e 'sleep int(rand(3600))'; systemctl stop apache2; ufw allow http
post_hook = ufw deny http; systemctl start apache2

Seems to work reasonably well so far … as long as your webserver must not stay online all the time of course.

Written by

Joerg Moellenkamp

Grey-haired, sometimes grey-bearded Windows dismissing Unix guy.