从基础到自动化监控的完整指南
目录导读
- 为什么需要证书过期检查脚本?
- 证书过期检查的核心原理
- 各语言脚本实现方案(Bash/Python/PowerShell)
- 生产环境自动化监控架构
- 常见问题与最佳实践
- 问答环节:你关心的证书检查问题
为什么需要证书过期检查脚本?
SSL/TLS证书是现代互联网安全的基础,但证书过期是导致服务中断的常见原因,据统计,超过60%的网站曾因证书未及时续期而出现安全警告或服务不可用,手动检查证书状态不可靠,因此编写自动化的证书过期检查脚本成为运维和开发人员的必备技能。

无论是网站、API接口还是内部服务,证书过期检查脚本能帮你:
- 提前发现即将过期的证书
- 减少因证书问题导致的业务中断
- 集成到监控系统(如Prometheus、Nagios)
- 支持批量检查和邮件/企业微信告警
证书过期检查的核心原理
所有证书检查脚本都基于两个核心操作:
从目标服务器获取证书
通过建立TCP连接(通常是443端口)并发起SSL/TLS握手,从服务器响应中提取证书内容,主要用到OpenSSL命令行或各编程语言的SSL库。
解析证书的有效期字段
证书中包含notBefore(生效时间)和notAfter(到期时间),脚本需要将当前时间与到期时间比较,计算剩余天数,并根据设定的阈值判断是否告警。
关键点:
- 必须校验证书链的完整性
- 注意不同协议端口(如HTTPS:443, SMTPS:465, IMAPS:993)
- 支持SNI(Server Name Indication),否则多域名证书无法正确验证
各语言脚本实现方案
Bash脚本(最轻量级,适合Linux环境)
#!/bin/bash
DOMAIN="example.com"
PORT="443"
WARN_DAYS=30
# 获取证书过期日期
expiry_date=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:$PORT 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
# 转换为时间戳
expiry_timestamp=$(date -d "$expiry_date" +%s)
current_timestamp=$(date +%s)
# 计算剩余天数
remaining_days=$(( (expiry_timestamp - current_timestamp) / 86400 ))
if [ $remaining_days -le 0 ]; then
echo "❌ 证书已过期!域名: $DOMAIN"
elif [ $remaining_days -le $WARN_DAYS ]; then
echo "⚠️ 证书将在 $remaining_days 天后过期,请尽快续期!"
else
echo "✅ 证书还有 $remaining_days 天过期,状态正常。"
fi
适用场景:快速检查单个域名,适合Cron定时任务。
Python脚本(功能丰富,易于扩展)
import ssl
import socket
from datetime import datetime, timedelta
def check_cert_expiry(hostname, port=443, warn_days=30):
context = ssl.create_default_context()
with socket.create_connection((hostname, port), timeout=5) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
cert = ssock.getpeercert()
expiry_str = cert['notAfter']
expiry_date = datetime.strptime(expiry_str, '%b %d %H:%M:%S %Y %Z')
remaining = (expiry_date - datetime.utcnow()).days
return remaining
# 批量检查
domains = ["example.com", "api.example.org", "mail.example.net"]
for domain in domains:
days = check_cert_expiry(domain)
if days < 0:
print(f"{domain}: 已过期!")
elif days < 30:
print(f"{domain}: 即将过期(剩{days}天)")
else:
print(f"{domain}: 正常(剩{days}天)")
适用场景:需要批量检查、输出JSON、集成到API服务中。
PowerShell脚本(Windows环境首选)
$domain = "example.com"
$warnDays = 30
$request = [Net.WebRequest]::Create("https://$domain")
$request.Timeout = 5000
try {
$response = $request.GetResponse()
$cert = $request.ServicePoint.Certificate
$expiry = $cert.GetExpirationDateString()
$remaining = ((Get-Date $expiry) - (Get-Date)).Days
if ($remaining -le 0) {
Write-Host "❌ $domain 证书已过期"
} elseif ($remaining -le $warnDays) {
Write-Host "⚠️ $domain 证书将在 $remaining 天后过期"
} else {
Write-Host "✅ $domain 证书正常,剩余 $remaining 天"
}
}
catch {
Write-Host "❌ 连接失败: $_"
}
适用场景:Windows服务器的IIS证书检查、Active Directory集成。
生产环境自动化监控架构
单域名脚本只适合调试,生产环境需要完整方案:
配置文件化管理
创建domains.txt或JSON/YAML文件,管理所有需要监控的域名、端口、阈值:
[
{"domain": "www.example.com", "port": 443, "warn_days": 30},
{"domain": "api.example.com", "port": 8443, "warn_days": 14}
]
定时任务触发
- Linux:Crontab每6小时执行一次
- Windows:Task Scheduler每日凌晨运行
- 建议:不要在高峰时段运行,避免额外网络负载
告警通知
- 邮件通知(使用smtplib或sendmail)
- 企业微信/钉钉Webhook
- Slack消息推送
- 与Prometheus AlertManager集成
日志与统计
将每次检查结果写入日志文件或数据库,便于排查问题和生成报表。
常见问题与最佳实践
Q:脚本检查结果与浏览器显示不一致?
A:可能是因为浏览器缓存了旧的证书,或者脚本未正确处理SNI,建议在openssl命令中添加-servername参数。
Q:如何检查证书链是否完整?
A:使用openssl s_client -showcerts查看整个证书链,确保中间证书已正确安装。
Q:脚本支持通配符域名吗?
A:支持,直接检查*.example.com,或者检查其对应的具体域名(如blog.example.com)。
最佳实践清单:
- 设置合理的告警阈值(建议:30天警告,7天紧急,3天红色)
- 避免在脚本中硬编码敏感信息(如邮件密码)
- 检查失败时应视为告警(可能网络问题或证书完全不可用)
- 对超时和SSL握手错误做异常处理
- 定期测试脚本本身(模拟证书过期环境)
问答环节:你关心的证书检查问题
问:免费证书检查脚本和商业证书检查有什么不同?
答:商业证书可能包含OCSP(在线证书状态协议)和CRL(证书吊销列表)验证,而免费脚本一般只检查有效期,如果需要吊销状态检查,建议集成OCSP stapling。
问:检查内部自签名证书需要注意什么?
答:自签名证书没有CA链,脚本需要使用-no-CApath或-CAfile指定信任的根证书,否则会报连接错误。
问:如何将脚本集成到CI/CD流水线?
答:在GitLab CI或Jenkins中,可以添加一个stage,在部署前检查证书状态,确保生产环境证书始终有效。
问:脚本检查会影响服务器性能吗?
答:每次检查仅创建一个TCP连接(约0.1-0.5秒),对于大多数服务器几乎没有影响,但如果监控数百个域名,建议控制并发数。
通过以上方案,你可以从零开始构建适合自己环境的证书过期检查脚本。证书检查不是一次性的工作,而应该成为运维自动化的一部分,定期运行并持续改进,如果你有特殊的证书检查需求(如检查文件中的证书、多级域名、CDN场景),可以在基础脚本上进行扩展。