-
-
Save cgmartin/49cd0aefe836932cdc96 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
TARGET="mysite.example.net"; | |
RECIPIENT="[email protected]"; | |
DAYS=7; | |
echo "checking if $TARGET expires in less than $DAYS days"; | |
expirationdate=$(date -d "$(: | openssl s_client -connect $TARGET:443 -servername $TARGET 2>/dev/null \ | |
| openssl x509 -text \ | |
| grep 'Not After' \ | |
|awk '{print $4,$5,$7}')" '+%s'); | |
in7days=$(($(date +%s) + (86400*$DAYS))); | |
if [ $in7days -gt $expirationdate ]; then | |
echo "KO - Certificate for $TARGET expires in less than $DAYS days, on $(date -d @$expirationdate '+%Y-%m-%d')" \ | |
| mail -s "Certificate expiration warning for $TARGET" $RECIPIENT ; | |
else | |
echo "OK - Certificate expires on $expirationdate"; | |
fi; |
Place all your domains in a file. Run the script in a loop, giving the loop a domain each time it runs. Maybe something like this:
#!/bin/bash
DOMAINS="/path/to/list/of/domains/list.txt"
RECIPIENT="[email protected]"
DAYS="7"
while read -r TARGET; do
echo "checking if $TARGET expires in less than $DAYS days";
expirationdate=$(date -d "$(: | openssl s_client -connect "$TARGET":443 -servername "$TARGET" 2>/dev/null \
| openssl x509 -text \
| grep 'Not After' \
|awk '{print $4,$5,$7}')" '+%s');
in7days=$(($(date +%s) + (86400*DAYS)));
if [ "$in7days" -gt "$expirationdate" ]; then
echo "KO - Certificate for $TARGET expires in less than $DAYS days, on $(date -d @"$expirationdate" '+%Y-%m-%d')" \
| mail -s "Certificate expiration warning for $TARGET" $RECIPIENT ;
else
echo "OK - Certificate expires on $expirationdate";
fi;
done<"${DOMAINS}"
Define your list of domains on line 3. I added some double quotes to his original script.
Cheers
How would i scan ports 443, 465, and 993, with human readable time format instead of epoch?
Hi,
I have getting an issue in the script once we pass the dummy url also the mail is sending with alert, how can we include that condition also in that script .
Eg:
unable to load certificate
140359043876160:error:0909006C:PEM routines:get_name:no start line:../crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
Once we got the above its should go to else part no need to send mail.
i recommend to also format the date for the success case
Instead of
echo "OK - Certificate expires on $expirationdate"; # OK - Certificate expires on 1658872800
do this
echo "OK - Certificate expires on $(date -d @$expirationdate '+%Y-%m-%d')"; # OK - Certificate expires on 2022-07-27
to fix some glitch's in Ubuntu: expirationdate=$(date -d "$(echo -n | openssl s_client -servername "$TARGET" -connect "$TARGET":"443" 2>&- | openssl x509 -enddate -noout | awk -F= '{print $2}')" +%s)
i am using this script
#!/bin/bash
TARGET="mysite.example.net";
RECIPIENT="[email protected]";
DAYS=7;
echo "checking if $TARGET expires in less than $DAYS days";
expirationdate=$(date -d "$(: | openssl s_client -connect $TARGET:443 -servername $TARGET 2>/dev/null
| openssl x509 -text
| grep 'Not After'
|awk '{print $4,$5,$7}')" '+%s');
in7days=$(($(date +%s) + (86400*$DAYS)));
if [ $in7days -gt $expirationdate ]; then
echo "KO - Certificate for $TARGET expires in less than
| mail -s "Certificate expiration warning for $TARGET" $RECIPIENT ;
else
echo "OK - Certificate expires on $expirationdate";
fi;
i am getting this error:
checking if expires in less than 7 days
date: invalid date 'Jul 4 2023'
./checkssl2.sh: line 11: [: 1658487210: unary operator expected
OK - Certificate expires on
getting invalid date ?
can anyone help me @vadirajks @dahse89 @cgmartin
@Aabhusan : checkout below
#!/bin/bash
TARGET="example.net";
RECIPIENT="[email protected]";
DAYS=7;
echo "checking if $TARGET expires in less than $DAYS days";
expirationdate=$(date -d "$(echo -n | openssl s_client -servername "$TARGET" -connect "$TARGET":"443" 2>&- | openssl x509 -enddate -noout | awk -F= '{print $2}')" +%s)
in7days=$(($(date +%s) + (86400*$DAYS)));
if [ $in7days -gt $expirationdate ]; then
echo "KO - Certificate for (date -d @$expirationdate '+%Y-%m-%d')" | mailx -s "Certificate expiration warning for $TARGET" $RECIPIENT ;
else
echo "OK - Certificate expires on $expirationdate";
fi;
Place all your domains in a file. Run the script in a loop, giving the loop a domain each time it runs. Maybe something like this:
#!/bin/bash DOMAINS="/path/to/list/of/domains/list.txt" RECIPIENT="[email protected]" DAYS="7" while read -r TARGET; do echo "checking if $TARGET expires in less than $DAYS days"; expirationdate=$(date -d "$(: | openssl s_client -connect "$TARGET":443 -servername "$TARGET" 2>/dev/null \ | openssl x509 -text \ | grep 'Not After' \ |awk '{print $4,$5,$7}')" '+%s'); in7days=$(($(date +%s) + (86400*DAYS))); if [ "$in7days" -gt "$expirationdate" ]; then echo "KO - Certificate for $TARGET expires in less than $DAYS days, on $(date -d @"$expirationdate" '+%Y-%m-%d')" \ | mail -s "Certificate expiration warning for $TARGET" $RECIPIENT ; else echo "OK - Certificate expires on $expirationdate"; fi; done<"${DOMAINS}"
Define your list of domains on line 3. I added some double quotes to his original script.
Cheers
Hi,
I'm a new user of Linux can you please explain this "$(: ". the exact usage of this command,
without this line, "while read" exited after the first-line executed
thanks
This is how I got it working
#!/bin/bash
file=$(cat /path/to/list/of/domains/list.txt)
RECIPIENT="[email protected]"
DAYS="3"
for line in $file; do
echo "checking if $line expires in less than $DAYS days";
expirationdate=$(date -d "$(: | openssl s_client -connect "$line":443 -servername "$line" 2>/dev/null \
| openssl x509 -text \
| grep 'Not After' \
|awk '{print $4,$5,$7}')" '+%s');
indays=$(($(date +%s) + (86400*DAYS)));
if [ "$indays" -gt "$expirationdate" ]; then
echo "expiring soon"
echo "KO - Certificate for $line expires in less than $DAYS days, on $(date -d @"$expirationdate" '+%Y-%m-%d')" \
| mail -s "Certificate expiration warning for $line" $RECIPIENT ;
else
echo "OK - Certificate expires on $(date -d @"$expirationdate" '+%Y-%m-%d')";
fi;
done
exit 0
Amazing script! Just what i needed as base to build on :)
I changed it quite a bit to be an alternative to LetsEncrypt expiry mails. Here's my version:
#!/bin/bash
# Configuration
DOMAIN_LIST_FILE="/home/mark/domain_ssl_ttl_check.txt"
EXPIRY_DAYS=(14 10 7 5 3 2 1)
NOTIFICATION_SCRIPT="/home/mark/notify.sh"
# Function to get certificate expiry timestamp
get_expiry_timestamp() {
local domain="$1"
date -d "$(: | openssl s_client -connect "$domain":443 -servername "$domain" 2>/dev/null \
| openssl x509 -text \
| grep 'Not After' \
| awk '{print $4,$5,$7}')" '+%s' 2>/dev/null
}
# Function to calculate days until expiry
days_until_expiry() {
local expiry_timestamp="$1"
local current_timestamp=$(date +%s)
local seconds_diff=$((expiry_timestamp - current_timestamp))
echo $((seconds_diff / 86400))
}
# Main loop
while IFS= read -r base_domain; do
echo "Checking certificate expiry for: $base_domain"
expiry_timestamp=$(get_expiry_timestamp "$base_domain")
if [ -z "$expiry_timestamp" ]; then
echo "Error: Could not retrieve certificate information for $base_domain. Skipping."
continue
fi
days_left=$(days_until_expiry "$expiry_timestamp")
expiry_date=$(date -d @"$expiry_timestamp" '+%d-%m-%Y')
echo "Certificate for $base_domain expires in $days_left days, on $expiry_date."
triggered=false # Flag to track if the notification script was triggered
for trigger_days in "${EXPIRY_DAYS[@]}"; do
if [ "$days_left" -eq "$trigger_days" ] && [ -x "$NOTIFICATION_SCRIPT" ]; then
title="Certificate Expiry Warning"
content="The SSL certificate for '$base_domain' and '*.${base_domain}' will expire in $days_left days, on $expiry_date."
echo "Triggering notification script for $base_domain - $days_left days remaining"
"$NOTIFICATION_SCRIPT" "$title" "$content"
triggered=true
break
elif [ "$days_left" -eq "$trigger_days" ] && [ ! -x "$NOTIFICATION_SCRIPT" ]; then
echo "Warning: Notification script '$NOTIFICATION_SCRIPT' is not executable."
triggered=true
break
fi
done
if [ "$triggered" = false ]; then
echo "No immediate notification for $base_domain. Expires on $expiry_date."
fi
done < "$DOMAIN_LIST_FILE"
exit 0
Yes, i used AI to make this better :)
A couple things to note:
- First of, day-month-year. (it used to be year-month-day, yuck)
DOMAIN_LIST_FILE
is a one line per domain file- in my case i'm exclusively using wildcard domains so the message i get says foo.bar and *.foo.bar, this might not be applicable to others.
EXPIRY_DAYS
, a list of specific expiry days to handle. This is for the notification (or mail in the old version). I didn't want to maintain a temp file so i solved it by just having a fixed list of days where you can receive a notification.NOTIFICATION_SCRIPT
, the first argument is the title, second is the expiry message. In my case i'm using home assistant and thus have the "luxury" of using it's notification API to send me an actual notification.
The script can probably be simplified a little but this works really nice!
Run this as a daily cronjob and you're all set for domain expiry notifications.
Here is the notify.sh
script, change where needed.
#! /bin/bash
curl -X POST \
-H "Authorization: Bearer [TOKEN]"
-H "Content-Type: application/json" \
-d "{ \
\"title\": \"$1\", \
\"message\": \"$2\" \
}" \
[HA]/api/services/notify/[DEVICE]
I had to change things on the links i found so i guess those resources have changed compared to how home assistant works now. Therefore not posting links :)
- First of, day-month-year. (it used to be year-month-day, yuck)
You said year-month-day, yuck, it has to be the most dumbest thing thing in this script. Year-month-day is the standard in programming.
- First of, day-month-year. (it used to be year-month-day, yuck)
You said year-month-day, yuck, it has to be the most dumbest thing thing in this script. Year-month-day is the standard in programming.
Lol ๐ then you change it to what you like.
There's a couple reasons why i made that change.
- We - western people - read from left to right. The most important part of the date in this context is the day and potentially the month. Having that readable from left to right makes a lot of sense (to me!).
- Same geographic argument, different reason. dd-mm-yyyy is the standard here, i'm used to that and can't stand the many differences.
As an aside, if year-month-day is a standard (didn't know that and I've been a programmer for decades by now), then i'll happily ignore that. I'll quote you for my reason: "it has to be the most dumbest thing" ๐
Working great, thanks very much for the script!
How to add multiple targets ?
@cgmartin