TroubleChute Logo

Certbot post-hook setup for Mailcow-Dockerized

Published: Nov 16, 2022
Last Edit: Nov 20, 2022
436 Words, 2 Minutes.


Well, the title is a mouthful, but hear me out.

If you host a mail server using Mailcow-Dockerized, and you ONLY run a mail server (no web server) - it can auto-renew its SSL certificates. Sounds good.

However, if you’re running a web server or other services on port 80 or 443, such as an entire website: the Mailcow-Dockerized ACME client can’t check and renew SSL certificates if you’re using something like an NGINX Reverse Proxy.

Using this, you can host multiple subdomains, and other services on one domain, using just a single port 80 or 443.

If you’re using an NGINX Reverse Proxy, you’re likely using Certbot to manage your SSL renewals. The only issue is that Docker doesn’t know about changes to the filesystem of your host where your NGINX server is running (more than likely).

So, all we need to do is copy the renewed SSL certificates every time Certbot deploys them. Easy, right? But how?

Setting up a Post-hook

Let’s set up a post-hook event for Certbot. It will automatically copy the renewed SSL certificates every time Certbot deploys them, and restart the docker container.

The Mailcow-Dockerized docs talk about setting this up, but provide no more info.

We will use their script as our post-hook script (You will see it later on).

Creating the script file

Certbot has a simple directory structure for setting up these scripts:


Inside this folder, we have deploy, post, and pre. All self-explanatory.

We’ll be creating a new file in the deploy directory as follows:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
if [ "$RENEWED_LINEAGE" = /etc/letsencrypt/live/my.domain.tld ]
    cp /etc/letsencrypt/live/my.domain.tld/fullchain.pem /opt/mailcow-dockerized/data/assets/ssl/cert.pem
    cp /etc/letsencrypt/live/my.domain.tld/privkey.pem /opt/mailcow-dockerized/data/assets/ssl/key.pem
    postfix_c=$(docker ps -qaf name=postfix-mailcow)
    dovecot_c=$(docker ps -qaf name=dovecot-mailcow)
    nginx_c=$(docker ps -qaf name=nginx-mailcow)
    docker restart ${postfix_c} ${dovecot_c} ${nginx_c}

(Remember to change my.domain.tld to the correct domain you have set up with Certbot)

Make sure the files exist as well!

Finally, make sure to set the file to an executable one:

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/ (in my case)

Running the script once

Now that we’ve got auto-renew set up as a post-hook, let’s run the script once just to refresh things. You’ve likely found your way to this because you’re seeing errors in the ACME logs, so here we go.

Simply execute: /etc/letsencrypt/renewal-hooks/deploy/, and watch it run.

Check the logs

Now, we can make sure that everything is happily running and set up as it should be.

Go to your Mailcow-Dockerized client and sign in.

Click Configuration, System Information, then under Logs select ACME.

TCNO TechNobo / TroubleChute © Wesley Pyburn (TechNobo / TroubleChute)