背景
我的服务器上安装了宝塔服务器管理系统 ,看到计划任务里有一条任务是 续签Let's Encrypt证书,但是网站ssl证书过期后不会自动续签,也没有查什么原因,写了一个小代码,可以自动续签分享给大家共用,如果你们知道原有的宝塔代码为什么不能续签的原因,也可以后面留言共勉。
操作
把如下代码存入于 /www/server/panel/class/auto_letsencrypt_v2.py , 文件中需要修改你想要指定的过期天数和过滤不续签的域名等。因为这段代码,会读取所有证书夹里的域名,由于有的网站现在不用了,但证书夹里不存在其证书痕迹。可以把不用的网站从证书夹中删除,就不用过滤了。
# -*- encoding: utf-8 -*-
# SSL证书 Let's Encrypt自动续签, 加入计划任务, 每天夜间执行
import json
import time
import subprocess
import os
import glob
conf = "/www/server/panel/config/letsencrypt_v2.json"
log_file = "/www/server/panel/class/renew_cert_log.txt"
# 单日志上限1MB
max_log_size = 1 * 1024 * 1024
# 最多保留10份备份日志
max_backup_count = 10
def write_log(msg):
if os.path.exists(log_file) and os.path.getsize(log_file) > max_log_size:
backup_name = log_file + "." + time.strftime("%Y%m%d_%H%M%S")
os.rename(log_file, backup_name)
backup_list = sorted(glob.glob(log_file + ".*"))
if len(backup_list) > max_backup_count:
for old_file in backup_list[: len(backup_list) - max_backup_count]:
os.remove(old_file)
t = time.strftime("%Y-%m-%d %H:%M:%S")
line = f"[{t}] {msg}"
print(line)
with open(log_file, "a", encoding="utf-8") as f:
f.write(line + "\n")
with open(conf, "r", encoding="utf-8") as f:
data = json.load(f)
orders = data.get("orders", {
})
now = int(time.time())
# 续签30天内的,证书在30天内到期的才会续签,这里可以根据自己的需要设置
expire_days = 30
# ==========排除域名列表,在这里的域名不会续签 ==========
exclude_domains = {
"hao366.net",
}
# ==============================
# 标记是否有任意订单续签成功
has_success = False
write_log("===== 证书自动续签任务开始 =====")
for k, v in orders.items():
cert_timeout = v.get("cert_timeout", 0)
domains = v.get("domains", [])
auth_type = v.get("auth_type", "http")
auth_path = v.get("auth_to", "")
need_skip = False
for d in domains:
if d in exclude_domains:
need_skip = True
break
if need_skip:
write_log(f"跳过废弃域名订单: {domains}")
continue
if not domains or auth_type != "http" or not auth_path:
write_log(f"跳过非http验证/信息不全订单: {domains}")
continue
left = (cert_timeout - now) / 86400
if left < expire_days:
domain_str = ",".join(domains)
write_log(f"开始续签 {domain_str} 剩余{left:.2f}天")
cmd = [
"/www/server/panel/pyenv/bin/python3",
"/www/server/panel/class/acme_v2.py",
"--domain",
domain_str,
"--type",
"http",
"--path",
auth_path,
]
ret = subprocess.run(cmd)
if ret.returncode == 0:
write_log(f"✅ {domain_str} 续签成功")
has_success = True
else:
write_log(f"❌ {domain_str} 续签失败!继续下一个订单")
# 全部订单循环结束后,如果有成功,统一执行一次
if has_success:
write_log("存在续签成功域名,执行nginx重载 + 重载宝塔面板")
subprocess.run(["systemctl", "reload", "nginx"])
subprocess.run(["bt", "4"])
write_log("===== 证书自动续签任务结束 =====")
然后在编辑计划任务里的 “续签Let's Encrypt证书” 那条任务,如下
python3 /www/server/panel/class/auto_letsencrypt_v2.py
当然,如果你使用的python虚拟环境,可以根据情况把python3变为你的虚拟环境的地址。搞完每天夜间会执行,下面是执行日志,现在看到的是没有要续签的证书。
运行后的日志
[2026-10-23 03:13:01] ===== 证书自动续签任务开始 =====
[2026-10-23 03:13:01] 跳过废弃域名订单: ['hao366.net']
[2026-10-23 03:13:01] ===== 证书自动续签任务结束 =====