I have a few environments where Certbot (and similar) scripts cannot renew SSL certificates without manual intervention, but I still need to know when the certificates are getting close to their expiration date.
This bash script will check a certificate’s expiration date, using cURL, and optionally send you an e-mail if the expiration date is within a given window of days.
The script is also available as a gist here:
gist.github.com/joho1968/0441f2c50d26efe784af09193b3ec438
The “bash icon” was sourced here:
hackaday.com/2018/01/19/linux-fu-custom-bash-command-completion/bash-icon/
#!/bin/bash
#
#
# Check expiration date of SSL certificate using cURL
#
# I'm sure there are a million ways to do this better, so feel free to.
# The script is not extremely fault tolerant, but "it works for me" :)
# You may need to --- modify --- this script to suit your environment.
#
# Joaquim Homrighausen, Sweden, some time in 2025
#
# (it's entirely intentional that this script does things in separate
# steps as opposed to a super compact and cryptic way, as is common
# with many bash-ninja-things)
#
#
# Function to show script usage
usage() {
echo "Usage: $0 -u CHECK_URL -e EXPIRE_DAYS [-a EMAIL_ADDRESS] [-s] [-v]"
echo " -u CHECK_URL The URL of the site, e.g. https://somesite.somedomain"
echo " -e EXPIRE_DAYS Warn this many days ahead of expiration"
echo " -a EMAIL_ADDRESS (Optional) Send expiration warning/notice to this e-mail address"
echo " -s (Optional) Send e-mail, otherwise just display status"
echo " -v (Optional) Be somewhat verbose"
exit 2
}
# Set defaults, etc.
DRY_RUN=true
VERBOSE=false
EXPIRE_DAYS=
EXPIRE_EMAIL=
EXPIRE_URL=
# Parse command line arguments
while getopts "u:e:a:s;v" opt; do
case $opt in
u) EXPIRE_URL=$OPTARG ;;
e) EXPIRE_DAYS=$OPTARG ;;
a) EXPIRE_EMAIL=$OPTARG ;;
s) DRY_RUN=false ;;
v) VERBOSE=true ;;
*) usage ;;
esac
done
# Check if all mandatory parameters are provided
if [ -z "${EXPIRE_DAYS}" ] || [ -z "${EXPIRE_URL}" ]; then
usage
fi
# Check if options require more parameters
if [ "${DRY_RUN}" == false ] && [ -z "${EXPIRE_EMAIL}" ]; then
echo -e "\n-s requires e-mail address to be specified\n"
usage
fi
# Fetch certificate information from specified URL
shopt -s lastpipe
CERT_DATE=`curl ${EXPIRE_URL} -vk 2>&1 | grep -w "expire date:" | cut -c 17-40`
CERT_DATE_ISO=`date -d "${CERT_DATE}" "+%F %H%M%S"`
CHECK_DATE_ISO=`date -d "${CERT_DATE}" "+%FT%H:%M:%S"`
# Make date pretty
CERT_DATE=`date -d "${CERT_DATE}" "+%d-%b-%Y"`
# Maybe show verbose output
if [ "${VERBOSE}" == true ]; then
echo "Certificate for ${EXPIRE_URL} expires on ${CERT_DATE}"
fi
#This is when certificate expires, minus our window
EXPIRE_CHECK=`date -d "${CHECK_DATE_ISO}Z - ${EXPIRE_DAYS} days" "+%F %H%M%S"`
#This is now
NOW_DATE=`date "+%F %H%M%S"`
#Now is greater than when the certificate expires, minus our window
if [ "${NOW_DATE}" \> "${EXPIRE_CHECK}" ]; then
if [ "${DRY_RUN}" == true ]; then
if [ "${VERBOSE}" == true ]; then
echo "Certificate will expire within ${EXPIRE_DAYS} days (not sending e-mail)"
fi
else
if [ "${VERBOSE}" == true ]; then
echo "Will expire within ${EXPIRE_DAYS} days, Sending e-mail to ${EXPIRE_EMAIL}"
fi
#You may need to change "mail -s" to whatever works for you
#You should also probably change the -r parameter :)
echo -e "\n\nCertificate for ${EXPIRE_URL} expires within ${EXPIRE_DAYS} day(s) (on ${CERT_DATE})\n" | mail -r checkSSLexpired -s "Certificate for ${EXPIRE_URL} expires within ${EXPIRE_DAYS} day(s)" ${EXPIRE_EMAIL}
fi
exit 1
else
if [ "${VERBOSE}" == true ]; then
echo "Certificate will NOT expire within ${EXPIRE_DAYS} days"
fi
exit 0
fi