SSL/TLS alerts

SSL certificate expiry alerts to your phone.

A daily cron check with openssl + Nerve. Know before your cert expires, not after your users report "Not Secure".

Why monitor SSL expiry

Let's Encrypt auto-renewal is great until it silently fails. A DNS change, a firewall rule, or a misconfigured Certbot hook — and your cert expires without warning. Browsers show scary "Not Secure" banners, APIs start rejecting TLS, and users leave.

Single domain check

#!/bin/bash
# /usr/local/bin/nerve-ssl-check.sh
export NERVE_DSN="nerve://TOKEN:[email protected]"
DOMAIN="example.com"
WARN_DAYS=14

EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN":443 2>/dev/null \
  | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)

if [ -z "$EXPIRY" ]; then
  echo "SSL CHECK FAILED: cannot reach $DOMAIN" | nerve send --severity critical
  exit 1
fi

EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null || date -jf "%b %d %T %Y %Z" "$EXPIRY" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

if [ "$DAYS_LEFT" -le 0 ]; then
  echo "SSL EXPIRED: $DOMAIN (expired ${DAYS_LEFT#-} days ago)" | nerve send --severity critical
elif [ "$DAYS_LEFT" -le "$WARN_DAYS" ]; then
  echo "SSL EXPIRING: $DOMAIN in $DAYS_LEFT days" | nerve send --severity alert
fi
# Run daily at 8 AM
0 8 * * * /usr/local/bin/nerve-ssl-check.sh

Multiple domains

#!/bin/bash
export NERVE_DSN="nerve://TOKEN:[email protected]"
WARN_DAYS=14

DOMAINS=(
  "example.com"
  "api.example.com"
  "dashboard.example.com"
  "staging.example.com"
)

for DOMAIN in "${DOMAINS[@]}"; do
  EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN":443 2>/dev/null \
    | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)

  if [ -z "$EXPIRY" ]; then
    echo "SSL UNREACHABLE: $DOMAIN" | nerve send --severity critical
    continue
  fi

  EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null || date -jf "%b %d %T %Y %Z" "$EXPIRY" +%s 2>/dev/null)
  DAYS_LEFT=$(( (EXPIRY_EPOCH - $(date +%s)) / 86400 ))

  if [ "$DAYS_LEFT" -le 0 ]; then
    echo "SSL EXPIRED: $DOMAIN" | nerve send --severity critical
  elif [ "$DAYS_LEFT" -le "$WARN_DAYS" ]; then
    echo "SSL EXPIRING: $DOMAIN in $DAYS_LEFT days" | nerve send --severity alert
  fi
done

After Certbot renewal

Add a deploy hook to notify you when renewal succeeds (or fails).

# /etc/letsencrypt/renewal-hooks/deploy/nerve-notify.sh
#!/bin/bash
export NERVE_DSN="nerve://TOKEN:[email protected]"
echo "SSL renewed: $RENEWED_DOMAINS on $(hostname)" | nerve send
chmod +x /etc/letsencrypt/renewal-hooks/deploy/nerve-notify.sh

GitHub Actions: scheduled SSL check

name: SSL Expiry Check
on:
  schedule:
    - cron: '0 8 * * *'

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: Check SSL
        env:
          NERVE_DSN: ${{ secrets.NERVE_DSN }}
        run: |
          go install github.com/nerve-ink/nerve-cli/cmd/nerve@latest
          for DOMAIN in example.com api.example.com; do
            DAYS=$(echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN":443 2>/dev/null \
              | openssl x509 -noout -enddate | cut -d= -f2 \
              | xargs -I{} bash -c 'echo $(( ($(date -d "{}" +%s) - $(date +%s)) / 86400 ))')
            if [ "$DAYS" -le 14 ]; then
              echo "SSL EXPIRING: $DOMAIN in $DAYS days" | nerve send --severity alert
            fi
          done

Quick start

go install github.com/nerve-ink/nerve-cli/cmd/nerve@latest
export NERVE_DSN="nerve://TOKEN:[email protected]"
echo "SSL EXPIRING: example.com in 7 days" | nerve send --severity alert

FAQ

How do I get notified before my SSL certificate expires?

Run a daily cron job that checks the expiry date with openssl s_client and sends a Nerve signal when it is within your threshold (e.g., 14 days).

Does this work with Let's Encrypt auto-renewal?

Yes. Even with auto-renewal, renewals can silently fail. This script catches it before the certificate actually expires.

Can I check multiple domains?

Yes. Loop over a list of domains and check each one. The script sends a separate alert for each domain close to expiry.