之前推荐过使用Certimate来进行证书的自动化部署。目前我的腾讯云、多吉云、服务器面板都接入的证书自动化,但是还有一个问题就是宝塔的证书还需要我去更新一遍。

之前的介绍文章:

Certimate上手:自搭建开源SSL证书申请续期平台,自动部署证书到服务器

使用Certimate部署Google证书,免费通配符证书申请

本着能减少操作就不要额外增加负担的原则,我想到了使用宝塔的计划任务来更新我的证书。如果还没有部署Certimate可以参考前面的教程文章。

设置面板SSL

因为我面板SSL的证书和网站证书一样(通配符证书),我们在Certimate中配置SSH的部署方式时,可以直接上传上去。

新增部署配置

设置证书保存位置

证书保存位置

/www/server/panel/ssl/certificate.pem

/www/server/panel/ssl/privateKey.pem

这个两个地址为宝塔面板SSL的证书地址,对应在

面板证书

更改这个SSL就相当于更改了这个位置的文件。

修改好了可以尝试部署,如果服务器上的证书成功更新,我们就可以使用脚本来更新其他网站的证书啦。

使用Python脚本

我们创建一个update_certificates.py文件,然后插入下面的内容。

注意!使用前须知

本脚本涉及服务器内文件操作,建议先看脚本的工作机制,然后决定是否直接使用还是定制修改。

使用这个脚本一定要满足你的证书是通配符证书,也就是所有网站的证书一致。例如我的所有网站都是zhheo.com的,就可以使用包含zhheo.com和*.zhheo.com的通配符证书,所有网站的证书一致才能直接使用此脚本。

此脚本将更换此服务器中所有网站的证书,如果你的服务器存在多个不同根域名的网站,请不要直接使用此脚本。例如同一个网站服务器存在a.com和b.cn,则注定不能直接使用此脚本,需要在文件夹的部分进行筛选。

此Python脚本作为基础参考,如果你有与我不同的情况,可以用GPT来进行修改,请勿盲目直接使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import os
import shutil
import re
import subprocess

def is_ip_address(string):
# 匹配IP地址的正则表达式
ip_pattern = r'^(\d{1,3}\.){3}\d{1,3}$'
if not re.match(ip_pattern, string):
return False
# 验证每个数字是否在0-255范围内
numbers = string.split('.')
return all(0 <= int(num) <= 255 for num in numbers)

def reload_nginx():
try:
subprocess.run(['sudo', 'service', 'nginx', 'reload'], check=True)
print("Nginx 服务已成功重新加载")
except subprocess.CalledProcessError as e:
print(f"重新加载 Nginx 服务失败: {str(e)}")

def update_certificates():
# 源证书和私钥的路径
source_cert = '/www/server/panel/ssl/certificate.pem'
source_key = '/www/server/panel/ssl/privateKey.pem'

# 证书目录
cert_dir = '/www/server/panel/vhost/cert'

# 检查源文件是否存在
if not os.path.exists(source_cert) or not os.path.exists(source_key):
print("错误:源证书或私钥文件不存在")
return

# 读取源证书和私钥内容
with open(source_cert, 'r') as f:
cert_content = f.read()
with open(source_key, 'r') as f:
key_content = f.read()

# 遍历证书目录
for domain_folder in os.listdir(cert_dir):
folder_path = os.path.join(cert_dir, domain_folder)

# 检查是否为目录,不是IP地址,且不是0.default
if (os.path.isdir(folder_path) and
not is_ip_address(domain_folder) and
domain_folder != '0.default'):

fullchain_path = os.path.join(folder_path, 'fullchain.pem')
privkey_path = os.path.join(folder_path, 'privkey.pem')

# 更新证书
if os.path.exists(fullchain_path):
try:
with open(fullchain_path, 'w') as f:
f.write(cert_content)
print(f"已更新证书: {fullchain_path}")
except Exception as e:
print(f"更新证书失败 {fullchain_path}: {str(e)}")

# 更新私钥
if os.path.exists(privkey_path):
try:
with open(privkey_path, 'w') as f:
f.write(key_content)
print(f"已更新私钥: {privkey_path}")
except Exception as e:
print(f"更新私钥失败 {privkey_path}: {str(e)}")

# 在更新完证书后重新加载 Nginx
reload_nginx()

if __name__ == '__main__':
try:
update_certificates()
print("证书更新完成")
except Exception as e:
print(f"发生错误: {str(e)}")

将此脚本保存在任意位置,我这里以存储在/www/wwwroot/heossl.zhheo.com/update_certificates.py为例。

创建计划任务

宝塔支持计划任务的创建。

创建计划任务

创建计划任务

因为Certimate的证书部署时间是每天8点,我们设置一个8:30的自动化任务即可。每天都会更新一下证书。这种方式虽然会导致过多的执行,但是相比webhook传输或者其他触发器更加安全。

使用root用户执行python运行脚本,例如:

python3 /www/wwwroot/heossl.zhheo.com/update_certificates.py

编辑好了尝试运行一下,看看日志是否正确。

日志

正确的日志