Menü schliessen
Created: February 5th 2025
Last updated: February 5th 2025
Categories: Linux,  Virtualmin
Author: Marcus Fleuti

Virtualmin - Letsencrypt Expiration Notification Emails : Automated SSL Certificate Monitoring - Bash Script with Email Alerts

Donation Section: Background
Monero Badge: QR-Code
Monero Badge: Logo Icon Donate with Monero Badge: Logo Text
82uymVXLkvVbB4c4JpTd1tYm1yj1cKPKR2wqmw3XF8YXKTmY7JrTriP4pVwp2EJYBnCFdXhLq4zfFA6ic7VAWCFX5wfQbCC

Automated SSL Certificate Monitoring for Virtualmin Servers: Essential Solution as Let's Encrypt Ends Email Notifications

The SSL certificate landscape is undergoing a significant change that affects millions of website owners. Let's Encrypt, one of the world's largest certificate authorities, has announced the end of their certificate expiration email notifications, effective June 4, 2025. This change makes automated certificate monitoring more crucial than ever for maintaining website security and preventing unexpected certificate expirations.

For Virtualmin server administrators managing multiple domains, this announcement introduces a new challenge. While Let's Encrypt cites increasing automation adoption and privacy concerns as key factors in their decision, many organizations still rely on these notifications as a safety net. The transition away from Let's Encrypt's notification system means that implementing a robust, self-managed monitoring solution is no longer just a best practice—it's a necessity.

This guide introduces a comprehensive automated monitoring solution that not only fills the gap left by Let's Encrypt's decision but provides enhanced capabilities for certificate management across your entire domain portfolio. By implementing this system before the June 2025 deadline, you'll ensure continuous security coverage and avoid the risks of unnoticed certificate expirations.

Understanding the Challenge of SSL Certificate Management

System administrators face several critical challenges when managing SSL certificates across multiple domains:

First, there's the timing challenge. SSL certificates expire at different times, and tracking these expiration dates manually becomes exponentially more difficult as your domain count increases. Missing a renewal deadline can lead to service interruptions, security warnings, and lost customer trust.

Second, there's the verification challenge. A certificate might be present on your server, but is it properly installed? Is it accessible on the correct port? Is the domain's DNS properly configured? These factors all affect whether your SSL certificates are functioning as intended.

Third, there's the communication challenge. In larger organizations, different teams need to know about impending certificate expirations. Without an automated notification system, crucial information might not reach the right people in time.

A Deep Dive into Our Monitoring Solution

Our solution addresses these challenges through a sophisticated yet maintainable bash script that integrates deeply with Virtualmin. Let's explore how each component contributes to a robust certificate monitoring system.

Core Components and Their Functions

At its heart, the solution consists of several interconnected components:

Domain Discovery and Validation: The script begins by querying Virtualmin for all SSL-enabled domains. This approach ensures we're always monitoring the current domain set, automatically including newly added domains and removing decommissioned ones. Each discovered domain undergoes DNS validation, ensuring we're not wasting resources checking certificates for domains with DNS issues.

Certificate Verification System: For each valid domain, the script performs comprehensive certificate checks using the ssl-cert-check utility. This isn't just a simple expiration date check—it validates the entire certificate chain, checks certificate accessibility on the specified port, and verifies the certificate matches the domain.

Manual Certificate Integration: Not all certificates are managed through Virtualmin. Some services, like mail servers or custom applications, might use standalone certificates. Our solution includes a flexible system for monitoring these certificates, allowing you to specify certificate paths and custom identifiers.

Intelligent Notification System: The solution implements a sophisticated notification system that goes beyond simple alerts. It categorizes issues by severity, aggregates related problems, and ensures notifications reach the right recipients. The system differentiates between various types of issues:

  • Certificate expiration warnings
  • DNS resolution failures
  • Certificate accessibility problems
  • Configuration mismatches

Understanding the Email Notification System

The email notification system deserves special attention as it's crucial for proactive certificate management. The script generates three distinct types of email notifications:

Success Notifications: These daily reports confirm that all certificates are valid and properly configured. While they might seem unnecessary, these "all clear" messages serve an important purpose—they confirm that the monitoring system itself is functioning correctly.

Warning Notifications: When certificates approach their expiration date (defined by the DAYS_BEFORE_WARNING setting), the system sends detailed warnings. These notifications include specific certificate details, remaining validity period, and affected domains.

Error Notifications: These urgent alerts indicate immediate problems requiring attention, such as DNS resolution failures or certificate configuration issues.

Implementation Guide

Implementing this monitoring solution requires careful attention to several components. Here's where you'll find the complete script code:

#! /bin/bash

# This script checks SSL certificate validity for all Virtualmin-managed domains
# It performs DNS resolution checks and sends email notifications for expiring certificates
# and any DNS resolution failures

# File paths and system configurations
# ===================================

# Manual certificate checks configuration
# This array allows you to specify local certificate files that should be checked directly
# Each entry should contain:
#   - path: The full path to the certificate file
#   - name: A descriptive name for the certificate (used in logs)
# Example entry: ("path=/path/to/cert.pem;name=Description of cert")
# Leave the array empty () if you don't have any manual checks to perform
MANUAL_CERT_CHECKS=(
    "path=/home/mail.lexo.ch/ssl.cert;name=Mail Server Certificate"
    # Add more certificates as needed, one per line:
    # "path=/path/to/another/cert.pem;name=Another Service Certificate"
    # "path=/etc/ssl/custom/cert.pem;name=Custom Service Certificate"
)

# Temporary file to store the list of domains to check
VM_DOMAIN_LIST=/tmp/vm_domain.lst

# Log file where SSL check results and errors will be stored
MAILLOG="/var/log/ssl-check-all-hosts.log"

# Path to the mail binary for sending notifications
MAIL_PATH="/usr/bin/mail"

# Email sender address for notifications
# This can be modified using the 'chfn' command to set the user's full name
# Example: sudo chfn -f "SSL Monitor" serveradmin
MAIL_SENDER="serveradmin@lexo.ch"

# Recipients who will receive SSL certificate status notifications
MAIL_RECIPIENTS="serveradmin@lexo.ch"

# Path to the Virtualmin binary for managing virtual servers
VIRTUALMIN_BIN="/usr/sbin/virtualmin"

# Number of days before certificate expiration when warnings should be sent
# Certificates expiring within this window will trigger notification emails
DAYS_BEFORE_WARNING=14

# Path to the ssl-cert-check utility for certificate verification
SSL_CERT_CHECK_BIN=/usr/bin/ssl-cert-check

# List of domains to exclude from SSL certificate checks
# Add domain names separated by spaces
# Example: "domain1.com domain2.com domain3.net"
EXCLUDED_DOMAINS="aa-nohost.tld"

# Status tracking variables
# =======================

# Tracks overall script status - changes to [ERROR] if any issues are found
ERROR_OK="[SUCCESS]"

# Boolean flag to track if any DNS resolution errors occurred
HAS_DNS_ERROR=false

# Functions
# =========

# Checks if a domain is in the exclusion list
# Parameters:
#   $1: Domain name to check
# Returns:
#   0 if domain should be excluded
#   1 if domain should be included
is_excluded() {
    local domain="$1"
    for excluded in $EXCLUDED_DOMAINS; do
        if [ "$domain" = "$excluded" ]; then
            return 0
        fi
    done
    return 1
}

# Parse a manual certificate check entry and perform the check
# Parameters:
#   $1: Entry string in format "path=/path/to/cert;name=Description"
# Returns:
#   0 on successful check
#   1 if the certificate file doesn't exist
check_manual_cert() {
    local entry="$1"
    local cert_path=$(echo "$entry" | sed 's/^path=\([^;]*\);.*$/\1/')
    local cert_name=$(echo "$entry" | sed 's/^.*;name=\(.*\)$/\1/')

    if [ ! -f "$cert_path" ]; then
        echo "Error: Certificate file not found: $cert_path ($cert_name)" >> "$MAILLOG"
        ERROR_OK="[ERROR]"
        return 1
    fi

    echo -e "\n=== Checking $cert_name ===" >> "$MAILLOG"
    ${SSL_CERT_CHECK_BIN} -e "$MAIL_SENDER" -a -E "$MAIL_SENDER" \
        -x ${DAYS_BEFORE_WARNING} -c "$cert_path" >> "$MAILLOG" 2>&1
    return 0
}

# Main Script Logic
# ================

# Verify required utilities are available
if [ -z "$MAIL_PATH" ]; then 
    echo "Cannot find [ mail ]. Is it installed?" > "$MAILLOG"
    ERROR_OK="[ERROR]"
fi

if [ -z "$SSL_CERT_CHECK_BIN" ]; then 
    echo "Cannot find [ ssl-cert-check ]. Is it installed?" > "$MAILLOG"
    ERROR_OK="[ERROR]"
fi

# Create temporary files for processing
# We use mktemp for security to avoid race conditions
TEMP_DOMAIN_LIST=$(mktemp)
DNS_ERROR_LOG=$(mktemp)

# Retrieve list of SSL-enabled domains from Virtualmin
"${VIRTUALMIN_BIN}" list-domains --with-feature ssl --name-only > "${TEMP_DOMAIN_LIST}"

# Process each domain, checking DNS resolution and applying exclusions
while IFS= read -r domain; do
    if ! is_excluded "$domain"; then
        # Verify DNS resolution before adding to check list
        if host "$domain" >/dev/null 2>&1; then
            # Add port 443 (HTTPS) to domain for SSL checking
            echo "${domain} 443" >> "${VM_DOMAIN_LIST}"
        else
            # Log DNS resolution failures
            echo "DNS resolution failed for ${domain}" >> "$DNS_ERROR_LOG"
            HAS_DNS_ERROR=true
            ERROR_OK="[ERROR]"
        fi
    fi
done < "${TEMP_DOMAIN_LIST}"

# Perform SSL certificate checks for all valid domains
${SSL_CERT_CHECK_BIN} -e "$MAIL_SENDER" -a -E "$MAIL_SENDER" \
    -p 443 -x ${DAYS_BEFORE_WARNING} -f "${VM_DOMAIN_LIST}" > "$MAILLOG" 2>&1

# Process manual certificate checks
if [ ${#MANUAL_CERT_CHECKS[@]} -gt 0 ]; then
    echo -e "\n=== Manual Certificate Checks ===" >> "$MAILLOG"
    for cert_entry in "${MANUAL_CERT_CHECKS[@]}"; do
        check_manual_cert "$cert_entry"
    done
fi

# If DNS errors occurred, append them to the mail log
if [ "$HAS_DNS_ERROR" = true ]; then
    echo -e "\n=== DNS Resolution Errors ===" >> "$MAILLOG"
    cat "$DNS_ERROR_LOG" >> "$MAILLOG"
fi

# Send email notification with appropriate success/error status
sudo -u "$MAIL_SENDER" "$MAIL_PATH" -s "${ERROR_OK} Daily SSL Certificate test protocol" \
    "$MAIL_RECIPIENTS" < "$MAILLOG"

# Clean up temporary files
rm -f "$TEMP_DOMAIN_LIST" "$DNS_ERROR_LOG" "$VM_DOMAIN_LIST"

Essential Dependencies

Before implementing the solution, ensure your system has these key components:

ssl-cert-check Utility: This core dependency handles the certificate verification process. Installation varies by distribution:

sudo apt-get install ssl-cert-check  # For Debian/Ubuntu
sudo yum install ssl-cert-check      # For CentOS/RHEL

Mail Sending Capability: The script relies on the system's mail sending capabilities. Most Linux distributions include this by default, but you might need to install the mailutils package:

sudo apt-get install mailutils

Customizing the Sender Identity

To make your monitoring emails more professional and easily identifiable, configure the sender's display name. This simple step significantly improves the usability of your monitoring system. The following example assumes a monitoring user with the name serveradmin:

sudo chfn -f "SSL Certificate Monitor" serveradmin

Best Practices and Advanced Usage

To get the most out of this monitoring solution, consider these advanced implementation strategies:

Run script as root

We recommend to run this script as root user in order to give it full access to all certificates you might have added to the MANUAL_CERT_CHECKS variable. The script was not fully tested under other circumstances.

Set up daily CRON

We recommend a daily script execution. For most situations, scheduling checks during low-traffic periods during weekdays ( Monday [1] until Friday [5] )is absolutely fine, since you will be notified 14 days (!) before a certificate will expire anyway. The following example will issue the script every morning at 04:00 am from Monday until Friday:

crontab -e

# Early morning check when traffic is low
00 04 * * 1-5 /path/to/ssl-check-all-hosts

Troubleshooting and Maintenance

Even the best monitoring systems require occasional maintenance and troubleshooting. Here's how to address common issues:

DNS Resolution Problems

When DNS resolution fails, follow this systematic approach:

  1. Verify local DNS resolver configuration in /etc/resolv.conf
  2. Check network connectivity to DNS servers
  3. Validate domain DNS settings in Virtualmin
  4. Test resolution from multiple locations to identify potential geographic issues
  5. If a host becomes invalid (e.g. because customer did not pay the domains' annual bill), you can (temporarily) add the domain name to the EXCLUDED_DOMAINS variable

Certificate Verification Issues

Certificate verification failures often stem from these common causes:

  1. Incomplete certificate chains
  2. Incorrect file permissions
  3. Port accessibility issues
  4. Certificate-domain mismatches

Comparative Analysis with Alternative Solutions

Feature This Solution Commercial Services Manual Monitoring
Initial Cost Free High Free
Automation Level Full Full None
Customization High Limited Full
Integration with Virtualmin Native Limited Manual
Maintenance Required Minimal None High

Conclusion: Preparing for the Future of Certificate Management

Let's Encrypt's decision to end expiration notification emails marks a significant shift in the SSL certificate landscape. This change reflects a broader industry movement toward automated, self-managed security solutions. As we approach the June 2025 deadline, implementing robust certificate monitoring becomes not just a best practice, but an essential component of any serious web infrastructure.

The automated monitoring solution presented in this guide offers more than just a replacement for Let's Encrypt's notifications. It provides a comprehensive approach to certificate management that aligns with modern security practices. By monitoring DNS resolution, validating certificate chains, and providing customizable alerts, this system helps prevent the cascade of problems that can arise from expired certificates—from lost customer trust to service interruptions.

The end of Let's Encrypt's notification service should serve as a catalyst for organizations to evaluate and upgrade their certificate management practices. Whether you manage a single domain or a complex multi-server environment, now is the time to implement automated monitoring. The solution detailed in this guide provides the foundation for a proactive, reliable certificate management strategy that will serve you well beyond the 2025 transition.

Remember that effective security is built on systematic, automated processes rather than manual checks or external reminders. As we move into this new era of certificate management, the organizations that thrive will be those that embrace automation and proactive monitoring. By implementing this solution today, you're not just solving an immediate challenge—you're building a sustainable foundation for your organization's security future.