-
-
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.