以前ssl证书可以免费申请一年期的,主要是手动维护域名证书,上传到宝塔、在传到腾讯云、阿里云这些服务的cdn,现在好了,各家ssl证书不再提供一年期了,只提供90天的有效期的ssl证书免费使用。
以前一年期还经常忘记换证书,现在三个月一换太痛苦了,这些证书的机构为了收费确实是没法搞了,太烦了就靠自动化脚本来更新吧,正常脚本插件 acme.sh 是支持域名自动申请、续签更换的,宝塔面板也是通过这个插件进行免费证书申请的。但因为前面加了cdn没法这么轻松的搞了。
开始的思路是通过acme.sh 脚本申请证书更新证书来着,后来发现可能会与宝塔面板交互脚本太多,我自己写了一个计划任务,让宝塔自己负责维护服务器上的ssl证书和续签等,不需要特殊配置,只需要配置好域名的解析api就可以自己续签ssl证书了。
宝塔续签的证书按目录存放,我写一个定时任务,每天扫描宝塔目录里的脚本与cdn的脚本对比,如果证书有更新则自动推送到cdn更换证书。具体思路和计划任务脚本如下。
支持配置多个域名证书和目录,只要在一台主机上就可以扫,使用前需要先安装集成的腾讯云接口脚本tccli并配置好。
#!/bin/bash
# 脚本使用宝塔的自动 SSL 申请程序,同步到腾讯云 CDN
# 脚本使用宝塔的自动ssl申请程序,申请到ssl证书后,在计划任务创建一个计划任务,通过脚本配置单独域名ssl证书推送到腾讯云的cdn文件夹,并设置为域名最新证书。
# 如果你没有宝塔面板,可以自己集成测acme.sh,宝塔也是集成的这个程序 https://github.com/acmesh-official/acme.sh
# 同步到tccli :先申请安装tccli,配置好腾讯云的api接口 https://cloud.tencent.com/document/product/440/34012
#思路来源:https://blog.jnn.icu/wildcard-cert-with-cdn-auto-renew/
# 脚本使用宝塔的自动 SSL 申请程序,同步到腾讯云 CDN
# 定义宝塔面板路径
bt_panel_path="/www/server/panel/vhost/cert"
# 定义多个域名列表和对应的证书存放目录,其他域名也可以,会循环。
declare -A domain_cert_paths=(
["www.5656t.com"]="$bt_panel_path/5656t.com"
["5656t.com"]="$bt_panel_path/5656t.com"
["1.5656t.com"]="$bt_panel_path/1.5656t.com"
)
# 循环处理每个域名
for domain in "${!domain_cert_paths[@]}"; do
cert_path="${domain_cert_paths[$domain]}"
# 检查域名的证书文件是否存在
if [ ! -d "$cert_path" ]; then
echo "SSL certificate for domain $domain not found in Baota panel."
continue
fi
# 读取本地证书文件
local_fullchain=$(cat "$cert_path/fullchain.pem")
local_privkey=$(cat "$cert_path/privkey.pem")
# 查询 CDN 配置信息
cdn_config=$(tccli cdn DescribeDomainsConfig --cli-unfold-argument --Filters.0.Name domain --Filters.0.Value "$domain" --Filters.0.Fuzzy False)
# 提取证书 ID
existing_cert_id=$(echo "$cdn_config" | grep -oP '"CertId":\s*"\K[^"]+' | sed 's/\\n/\n/g')
echo " $domain CertId is: $existing_cert_id"
# 检查是否存在现有的证书
if [ -n "$existing_cert_id" ]; then
# 获取证书详细信息
existing_cert_response=$(tccli ssl DescribeCertificateDetail --cli-unfold-argument --CertificateId "$existing_cert_id")
existing_fullchain=$(echo "$existing_cert_response" | grep -oP '"CertificatePublicKey":\s*"\K[^"]+' | sed 's/\\n/\n/g')
existing_privkey=$(echo "$existing_cert_response" | grep -oP '"CertificatePrivateKey":\s*"\K[^"]+' | sed 's/\\n/\n/g')
#echo "$existing_fullchain"
#echo "$local_fullchain"
#echo "$existing_privkey"
#echo "$local_privkey"
# 比较本地证书和现有证书是否一致,腾讯云返回的证书文件会有多余的换行符,需要去掉。。好坑
if [ "$(echo "$local_fullchain" | tr -d '\n')" == "$(echo "$existing_fullchain" | tr -d '\n')" ] && [ "$(echo "$local_privkey" | tr -d '\n')" == "$(echo "$existing_privkey" | tr -d '\n')" ]; then
echo "The local certificate for domain $domain is identical to the existing certificate on Tencent Cloud. No update needed."
else
echo "The local certificate for domain $domain is different from the existing certificate on Tencent Cloud. Updating..."
# 上传证书到腾讯云
upload_response=$(tccli ssl UploadCertificate --cli-unfold-argument --CertificatePublicKey "$local_fullchain" --CertificatePrivateKey "$local_privkey")
echo "Upload response: $upload_response"
# 获取证书ID
cert_id=$(echo $upload_response | grep -oP '"CertificateId":\s*"\K[^"]+')
if [ -z "$cert_id" ]; then
echo "Failed to upload certificate to Tencent Cloud for domain $domain."
continue
fi
echo "Certificate ID for domain $domain: $cert_id"
# 部署证书到腾讯云 CDN
deploy_response=$(tccli cdn ModifyDomainConfig --cli-unfold-argument --Domain "$domain" --Route 'Https.CertInfo.CertId' --Value "{\"update\":\"$cert_id\"}")
echo "Deploy response for domain $domain: $deploy_response"
fi
else
echo "No existing certificate found on Tencent Cloud for domain $domain. Uploading new certificate..."
# 上传证书到腾讯云
upload_response=$(tccli ssl UploadCertificate --cli-unfold-argument --CertificatePublicKey "$local_fullchain" --CertificatePrivateKey "$local_privkey")
echo "Upload response: $upload_response"
# 获取证书ID
cert_id=$(echo $upload_response | grep -oP '"CertificateId":\s*"\K[^"]+')
if [ -z "$cert_id" ]; then
echo "Failed to upload certificate to Tencent Cloud for domain $domain."
continue
fi
echo "Certificate ID for domain $domain: $cert_id"
# 部署证书到腾讯云 CDN
deploy_response=$(tccli cdn ModifyDomainConfig --cli-unfold-argument --Domain "$domain" --Route 'Https.CertInfo.CertId' --Value "{\"update\":\"$cert_id\"}")
echo "Deploy response for domain $domain: $deploy_response"
fi
done
echo "Done"
这个脚本是与chatgpt一起写的,排查bug,改逻辑,又改了很久才搞好。