服务器监控 网站可用,同时检查证书有效期

2026-04-05 08:27

cron添加一个定时任务,每小时执行一次。

0 * * * * /root/testServer.sh >> /root/testServer.log 2>&1

检查服务器启动了,并每天检查一次证书是不是过期,提前7天发送




#!/bin/bash

# 日志函数 - 带时间戳
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# 配置参数
TARGET_URL="https://jaxer.cc"
EMAIL_RECEIVER="jaxer@163.com"  # 替换为收件人邮箱

# 锁文件目录(用于控制证书检查频率)
LOCK_DIR="/tmp/check_service"
mkdir -p "$LOCK_DIR"
CERT_CHECK_LOCK="$LOCK_DIR/cert_check_$(date +%Y%m%d).lock"

# 获取域名(去掉 https:// 前缀)
DOMAIN=$(echo "$TARGET_URL" | sed -E 's|https?://||' | sed -E 's|/.*||')

# 检查证书过期时间的函数
check_certificate_expiry() {
    local domain=$1
   
    # 获取证书过期时间(Unix 时间戳)
    expiry_date=$(echo | openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | \
        openssl x509 -noout -enddate 2>/dev/null | \
        sed -n 's/notAfter=//p')
   
    if [ -z "$expiry_date" ]; then
        echo "无法获取证书信息"
        return 1
    fi
   
    # 将过期时间转换为 Unix 时间戳
    expiry_timestamp=$(date -d "$expiry_date" +%s 2>/dev/null || date -j -f "%b %d %H:%M:%S %Y %Z" "$expiry_date" +%s 2>/dev/null)
   
    if [ -z "$expiry_timestamp" ]; then
        echo "无法解析证书过期时间"
        return 1
    fi
   
    # 当前时间戳
    current_timestamp=$(date +%s)
   
    # 计算剩余天数
    days_until_expiry=$(( (expiry_timestamp - current_timestamp) / 86400 ))
   
    echo "$days_until_expiry"
    return 0
}

# 发送邮件的函数
send_email() {
    local subject=$1
    local body=$2
   
    echo -e "$body" | mailx -s "$subject" "$EMAIL_RECEIVER"
   
    if [ $? -eq 0 ]; then
        log "邮件发送成功"
    else
        log "邮件发送失败"
    fi
}

# ==================== 主程序 ====================

# 1. 检查 HTTPS 证书过期时间(仅对 HTTPS URL,每天只检查一次)
if [[ "$TARGET_URL" == https://* ]] && [[ ! -f "$CERT_CHECK_LOCK" ]]; then
    # 创建今日锁文件
    touch "$CERT_CHECK_LOCK"
    # 清理旧的锁文件(保留最近7天)
    find "$LOCK_DIR" -name "cert_check_*.lock" -mtime +7 -delete 2>/dev/null
    log "检查 HTTPS 证书过期时间..."
   
    days_left=$(check_certificate_expiry "$DOMAIN")
    check_result=$?
   
    if [ $check_result -eq 0 ]; then
        log "证书将在 $days_left 天后过期"
       
        # 如果证书将在 7 天内过期,发送提醒邮件
        if [ "$days_left" -le 7 ] && [ "$days_left" -ge 0 ]; then
            log "警告:证书即将过期!"
           
            CERT_SUBJECT="SSL证书即将过期提醒 - $DOMAIN"
            CERT_BODY="域名 $DOMAIN 的 SSL 证书将在 $days_left 天后过期。\n请及时更新证书以避免服务中断。\n\n过期日期: $(date -d "+$days_left days" "+%Y-%m-%d")"
           
            send_email "$CERT_SUBJECT" "$CERT_BODY"
        elif [ "$days_left" -lt 0 ]; then
            log "错误:证书已过期 ${days_left#-} 天!"
           
            CERT_SUBJECT="SSL证书已过期警告 - $DOMAIN"
            CERT_BODY="域名 $DOMAIN 的 SSL 证书已过期 ${days_left#-} 天!\n请立即更新证书!"
           
            send_email "$CERT_SUBJECT" "$CERT_BODY"
        fi
    else
        log "证书检查失败: $days_left"
    fi
else
    if [[ "$TARGET_URL" == https://* ]]; then
        log "证书检查今日已执行,跳过"
    fi
fi

# 2. 使用 curl 获取 HTTP 状态码
echo "检查服务可用性..."
response=$(curl -o /dev/null -s -w "%{http_code}" "$TARGET_URL")
status_code=$?

# 检查curl是否成功执行
if [ $status_code -ne 0 ]; then
    log "请求失败: curl 执行错误"
   
    # 发送邮件通知服务不可用
    SUBJECT="服务不可用 - $TARGET_URL"
    BODY="目标网页 $TARGET_URL 无法访问。\ncurl 执行错误,请检查服务是否正常运行。"
   
    send_email "$SUBJECT" "$BODY"
    exit 1
fi

# 检查状态码是否为404
if [ "$response" -eq 404 ]; then
    log "检测到 404 错误,正在发送邮件通知..."
   
    # 邮件主题和正文
    SUBJECT="网页请求失败 - $TARGET_URL"
    BODY="目标网页 $TARGET_URL 返回状态码 404。\n请检查服务是否正常运行。"

    send_email "$SUBJECT" "$BODY"
else
    log "请求成功,状态码: $response"
fi


# 工具配置 # linux