-
-
Save greenmoss/8ee9d4acd3a21df699cde2225a78399e to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash | |
# This script renews letsecnrypt SSL certificates using Cloudflare dns-1 renewal | |
# It assumes you are using Mailcow | |
set -euo pipefail | |
# REQUIRED set these: | |
[email protected] | |
your_domain=mail.your.domain # only tested with single domain | |
cloudflare_ini_path=/root/.cloudflare # add your Cloudflare file here, called cloudflare.ini | |
# OPTIONAL also set these: | |
log_file=/var/log/certbot-cloudflare.log # if you don't want any logs, change it to /dev/null | |
# send all output and errors to log file | |
exec 1>$log_file | |
exec 2>&1 | |
# log what we are doing | |
set -x | |
date # overwrite, no log rotate! | |
echo "starting renewal" | |
docker pull certbot/dns-cloudflare | |
docker run --rm \ | |
-v $cloudflare_ini_path/cloudflare.ini:/cloudflare.ini \ | |
-v /opt/mailcow-dockerized/data/assets/ssl:/etc/letsencrypt \ | |
certbot/dns-cloudflare \ | |
certonly -n --agree-tos -m $your_email \ | |
--dns-cloudflare --dns-cloudflare-credentials /cloudflare.ini \ | |
-d $your_domain | |
cd /opt/mailcow-dockerized/data/assets/ssl | |
newcerts=$(find live/$your_domain/ -mmin -5) | |
if [ -z "$newcerts" ]; then | |
echo "no renewals found, not restarting services" | |
exit | |
fi | |
ln -sfv live/$your_domain/privkey.pem key.pem | |
ln -sfv live/$your_domain/cert.pem cert.pem | |
cd ../../.. | |
function reload_ssl_service () { | |
service=$1 | |
port=$2 | |
echo "restarting SSL service $1 on port $2" | |
docker-compose restart $service | |
timeout 30 sh -c '\ | |
while ! \ | |
openssl s_client -showcerts -connect $0:$1 2>/dev/null </dev/null | openssl x509 -noout 2>/dev/null; do | |
# $0 and $1 are inside single quotes, which means they expand to the arguments provided to sh -c | |
sleep 1 | |
done' $your_domain $port | |
echo "$service SSL cert expiration" | |
openssl s_client -showcerts -connect $your_domain:$port 2>/dev/null </dev/null | openssl x509 -noout -text | grep 'Not After' | |
} | |
reload_ssl_service nginx-mailcow 443 | |
reload_ssl_service dovecot-mailcow 993 | |
reload_ssl_service postfix-mailcow 465 | |
date | |
echo "completed" |
I'm seeing a strange issue.
After running the script to do a forced renewal, I'm seeing different expiry dates. This is confirmed by the ./helper-scripts/expiry-dates.sh script.
It appears only nginx has the updated cert, dovecot and postfix still using the old.
Have you seen this as well?
Perhaps my problem is/was the starting point. In the beginning I initially used the mailcow builtin acme client to do pull the initial certs while temporarily opening up ports 80/443 inbound.
My first guess would be that the services didn't actually restart.
Logs indicate all 3 have successfully restarted. Restarting manually didn't make any difference.
I think the issue is path related. Mailcow docs say not to use simlinks for certs.
Built in acme client places certs in to /data/assets/ssl/{domain.com}. It appears /data/assets/ssl is then mapped to the containers as /etc/ssl/mail. Your script symlinks them to /data/assets/ssl directly. From there it gets confusing.
Perhaps there's been some changes to cert placement in the current version. (2023-05a).
Edit. Rereading the mailcow docs - specifically https://docs.mailcow.email/post_installation/firststeps-ssl/#how-to-use-your-own-certificate
Does indeed indicate
To use your own certificates, just save the combined certificate (containing the certificate and intermediate CA/CA if any) to data/assets/ssl/cert.pem and the corresponding key to data/assets/ssl/key.pem.
IMPORTANT: Do not use symbolic links! Make sure you copy the certificates and do not link them to data/assets/ssl.
I'm not sure how /data/assets/ssl/{domain.com} got created in my instance to begin with. It does have a date of few weeks ago, so perhaps it was made by the built in acme client. So the only change then is copying files rather than symlinking?
I'm seeing a strange issue.
After running the script to do a forced renewal, I'm seeing different expiry dates. This is confirmed by the ./helper-scripts/expiry-dates.sh script.
It appears only nginx has the updated cert, dovecot and postfix still using the old.
Have you seen this as well?
Perhaps my problem is/was the starting point. In the beginning I initially used the mailcow builtin acme client to do pull the initial certs while temporarily opening up ports 80/443 inbound.