首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python 实现HTTPS网站证书过期监控及更新

Python 实现HTTPS网站证书过期监控及更新

作者头像
用户11081884
发布2026-07-20 20:17:19
发布2026-07-20 20:17:19
210
举报

在HTTPS已成为标配的今天,一个即将过期的SSL/TLS证书轻则导致浏览器警告,重则直接中断服务,影响用户体验和业务连续性。手动管理成百上千个域名的证书到期时间,无异于一场噩梦。今天,我们就用Python打造一个轻量级的自动化监控与更新系统,让证书管理从此无忧。

一、 为什么需要自动化监控?

想象一下,凌晨三点,你的核心业务网站因为证书过期而无法访问,警报响起,团队被紧急唤醒… 这并非危言耸听,而是许多运维团队曾经历或担忧的场景。手动记录、人工巡检的方式在域名数量激增、多云混合部署的复杂环境下,极易出现疏漏。自动化监控的核心价值在于 “防患于未然” ,通过程序定期检查,在证书到期前足够长的时间(如30天)发出预警,为人工或自动更新预留充足的操作窗口。

二、 系统核心设计思路

  1. 数据源输入: 获取需要监控的域名列表。
  2. 状态探测: 检查域名是否启用了HTTPS。
  3. 信息提取: 对于启用了HTTPS的域名,获取其SSL证书的过期时间。
  4. 状态判定与告警: 计算剩余天数,若低于阈值则触发告警(邮件、钉钉、企业微信等)。
  5. 自动更新(可选): 对于支持API的云平台或证书管理服务,可集成自动更新逻辑。

三、 分步实现与代码示例

下面我们分模块实现核心功能。假设我们的域名列表存储在一个简单的文本文件 domains.txt 中,每行一个域名。

1. 获取域名列表(数据源)

代码语言:javascript
复制
# 从文件读取域名列表
defload_domains(file_path='domains.txt'):
    withopen(file_path, 'r') asf:
        # 去除空行和前后空格
        domains = [line.strip() forlineinfifline.strip()]
    returndomains

# 示例:domains.txt 内容
# www.example.com
# api.example.com
# blog.example.org

2. 检查HTTPS支持我们使用 requests 库尝试访问域名的HTTPS端口,并设置合理的超时时间。

代码语言:javascript
复制
importrequests
fromrequests.exceptionsimportSSLError, ConnectionError, Timeout

defcheck_https_support(domain, timeout=5):
    url = f'https://{domain}'
    try:
        # 仅发起HEAD请求,节省带宽,只关心连接和证书状态
        response = requests.head(url, timeout=timeout, allow_redirects=True)
        # 如果请求成功(包括重定向),则认为支持HTTPS
        returnTrue, None
    exceptSSLErrorase:
        # SSL错误,可能证书无效或不匹配
        returnFalse, f"SSL Error: {e}"
    except (ConnectionError, Timeout) ase:
        # 连接超时或错误,可能未启用HTTPS或网络不通
        returnFalse, f"Connection Error: {e}"
    exceptExceptionase:
        returnFalse, f"Unexpected Error: {e}"

# 使用示例
domain = 'www.example.com'
https_enabled, error_msg = check_https_support(domain)
ifhttps_enabled:
    print(f"{domain} 支持HTTPS")
else:
    print(f"{domain} HTTPS检查失败: {error_msg}")

3. 获取证书过期时间这里我们使用 ssl 标准库和 cryptography 库(比 pyopenssl 更现代、维护更好)来获取证书信息。

代码语言:javascript
复制
importssl
importsocket
fromdatetimeimportdatetime
fromcryptographyimportx509
fromcryptography.hazmat.backendsimportdefault_backend

defget_cert_expiry_date(domain, port=443):
    try:
        # 创建原始socket连接
        sock = socket.create_connection((domain, port), timeout=10)
        context = ssl.create_default_context()
        # 包装socket为SSL socket
        ssock = context.wrap_socket(sock, server_hostname=domain)
        # 获取二进制格式的证书
        cert_bin = ssock.getpeercert(binary_form=True)
        ssock.close()
        sock.close()
        
        # 使用cryptography解析证书
        cert = x509.load_der_x509_certificate(cert_bin, default_backend())
        # 获取证书过期时间
        expiry_date = cert.not_valid_after
        returnTrue, expiry_date
    exceptExceptionase:
        returnFalse, f"Failed to get certificate for {domain}: {e}"

defget_days_until_expiry(expiry_date):
    """计算证书剩余有效天数"""
    now = datetime.utcnow()  # 证书时间通常是UTC
    delta = expiry_date-now
    returndelta.days

# 使用示例
domain = 'www.example.com'
success, expiry = get_cert_expiry_date(domain)
ifsuccess:
    days_left = get_days_until_expiry(expiry)
    print(f"域名 {domain} 的证书将于 {expiry} 过期,剩余 {days_left} 天。")
else:
    print(expiry)  # 输出错误信息

4. 整合与定时任务将上述模块整合,并加入告警逻辑。我们可以使用 schedule 库或操作系统级的 cron/Task Scheduler 来定时执行。

代码语言:javascript
复制
importjson
fromdatetimeimportdatetime

defmonitor_domains(domain_list, alert_threshold_days=30):
    results = []
    alert_list = []
    
    fordomainindomain_list:
        print(f"正在检查 {domain}...")
        # 检查HTTPS
        https_ok, _ = check_https_support(domain)
        ifnothttps_ok:
            results.append({'domain': domain, 'https': False, 'error': 'HTTPS not supported or unreachable'})
            continue
        
        # 获取证书信息
        cert_ok, cert_data = get_cert_expiry_date(domain)
        ifnotcert_ok:
            results.append({'domain': domain, 'https': True, 'error': cert_data})
            continue
        
        # 计算剩余天数
        days_left = get_days_until_expiry(cert_data)
        
        record = {
            'domain': domain,
            'https': True,
            'expiry_date': cert_data.isoformat(),
            'days_left': days_left,
            'check_time': datetime.utcnow().isoformat()
        }
        results.append(record)
        
        # 触发告警判断
        ifdays_left<= alert_threshold_days:
            alert_list.append(record)
            # 此处可以调用发送告警的函数,例如 send_alert(record)
            print(f"【告警】域名 {domain} 证书剩余 {days_left} 天即将过期!")
    
    # 将本次监控结果保存为JSON日志文件
    log_filename = f"cert_monitor_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.json"
    withopen(log_filename, 'w') asf:
        json.dump({'check_time': datetime.utcnow().isoformat(), 'results': results}, f, indent=2)
    
    returnresults, alert_list

# 主程序
if__name__ == '__main__':
    domains = load_domains('domains.txt')
    monitor_domains(domains, alert_threshold_days=30)

5. 进阶:集成自动更新(以Let’s Encrypt为例)对于使用 Let‘s Encrypt 免费证书的场景,可以集成 certbot 的自动化命令。

代码语言:javascript
复制
importsubprocess
importlogging

defauto_renew_certbot(domain):
    """
    使用certbot自动续签指定域名的证书。
    前提:服务器上已安装并配置好certbot。
    """
    try:
        # 使用--dry-run先测试,实际运行时移除--dry-run
        cmd = ['sudo', 'certbot', 'renew', '--cert-name', domain, '--dry-run']
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
        
        ifresult.returncode == 0:
            logging.info(f"证书续签模拟成功 for {domain}")
            # 模拟成功,实际续签(移除--dry-run)
            # cmd = ['sudo', 'certbot', 'renew', '--cert-name', domain]
            # subprocess.run(cmd, check=True)
            returnTrue, "Renewal simulation successful"
        else:
            logging.error(f"证书续签模拟失败 for {domain}: {result.stderr}")
            returnFalse, result.stderr
    exceptsubprocess.TimeoutExpired:
        logging.error(f"证书续签命令超时 for {domain}")
        returnFalse, "Command timeout"
    exceptExceptionase:
        logging.error(f"证书续签过程异常 for {domain}: {e}")
        returnFalse, str(e)

# 可以在告警逻辑中,对满足条件的域名调用自动更新
# if days_left <= 7: # 剩余7天时尝试自动更新
#     auto_renew_certbot(domain)

四、 部署与优化建议

  • 安全存储密钥: 如果使用云API,务必通过环境变量或密钥管理服务存储 AccessKey,切勿硬编码在代码中。
  • 结果持久化: 将监控结果存入数据库(如SQLite、MySQL)或时序数据库(如InfluxDB),便于历史查询和趋势分析。
  • 多样化告警: 除了控制台打印,集成邮件、钉钉机器人、企业微信、Slack等告警渠道。
  • 容器化部署: 使用Docker将监控程序容器化,便于在任意环境部署和扩展。
  • 监控程序本身: 别忘了为这个监控脚本也设置一个健康检查,确保它自己一直在正常运行。

通过以上约150行代码的核心框架,构建了一个HTTPS证书过期监控系统的雏形。它麻雀虽小,五脏俱全,涵盖了从数据采集、状态判断到告警触发的基本流程。你可以根据实际运维环境,轻松扩展数据源(从云API、CMDB获取域名)、丰富告警策略、对接不同的证书更新接口。

如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Nicholas与Pypi 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档