Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Aterfax/a66b3d566fad83f7928d327baf6cd402 to your computer and use it in GitHub Desktop.
Save Aterfax/a66b3d566fad83f7928d327baf6cd402 to your computer and use it in GitHub Desktop.
SWAG + Mailcow - syncing cert renewal actions

SWAG + Mailcow docker - syncing cert renewal actions

Motivation

Since you cannot prod Mailcow docker containers to restart from the certbot context within the SWAG docker container, we can just use some bash and systemd on the host.

Bash Script

Note that your host will need inotify-tools installed, e.g. apt install inotify-tools

/opt/mailcow-letsencrypt-watcher.sh

#!/bin/bash

# Source symlinks
DOMAIN="myfqdn.com"
SWAG_DIR="/opt/swag/config"
CERT_DIR="${SWAG_DIR}/etc/letsencrypt/live/${DOMAIN}"
PRIVKEY_SYMLINK="${CERT_DIR}/privkey.pem"
FULLCHAIN_SYMLINK="${CERT_DIR}/fullchain.pem"

# Destination paths
KEY_DEST="/opt/mailcow-dockerized/data/assets/ssl/key.pem"
CERT_DEST="/opt/mailcow-dockerized/data/assets/ssl/cert.pem"

# Function to monitor symlink changes and handle events
monitor_symlinks() {
    while true; do
        # Note that Letsencrypt will remove the $SWAG_DIR/config/etc/letsencrypt/live/$DOMAIN path temporarily
        # during renewal, so inotifywait can fail to start during this time.

	# inotify will output in the form of full path, event type, and filename whitespace separated.
        inotifywait -e modify,move,create,delete "$(dirname "$FULLCHAIN_SYMLINK")" |
            while read path event file; do
                echo "Event detected: $event on $file"
                sleep 120 # Wait for letsencrypt to finish
                cp "$PRIVKEY_SYMLINK" "$KEY_DEST"
                cp "$FULLCHAIN_SYMLINK" "$CERT_DEST"
                echo "Restarting Mailcow docker containers."
		# See: https://docs.mailcow.email/post_installation/reverse-proxy/r_p/#optional-post-hook-script-for-non-mailcow-acme-clients
                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}
            done
        # Add a short delay to prevent high CPU usage if inotifywait fails to start.
        sleep 1
    done
}

# Initial copy of symlink targets when service starts
cp "$PRIVKEY_SYMLINK" "$KEY_DEST"
cp "$FULLCHAIN_SYMLINK" "$CERT_DEST"

# Start monitoring
monitor_symlinks

Systemd script

/etc/systemd/system/mailcow-letsencrypt-watcher.service

[Unit]
Description="Mailcow Let's Encrypt Watcher"
After=network.target

[Service]
Type=simple
User=root
ExecStart=/opt/mailcow-letsencrypt-watcher.sh
Restart=always

[Install]
WantedBy=multi-user.target

Then enable and start it:

sudo systemctl daemon-reload  # Reload systemd to read the new unit file
sudo systemctl enable mailcow-letsencrypt-watcher.service  # Enable the service to start on boot
sudo systemctl start mailcow-letsencrypt-watcher.service  # Start the service
sudo systemctl status mailcow-letsencrypt-watcher.service  # Check service status
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment