一、先搞清楚:你要的是"批量申请"还是"批量续签"
这两个场景不一样,方案也不同:二、方案一:面板自带批量申请(10个站点以内)
这是最简单的方法,不需要任何代码,纯鼠标操作。2.1 操作步骤
① 进入宝塔面板 → 网站列表页
② 勾选左侧复选框,选中所有需要部署SSL的站点
③ 顶部操作栏点击 SSL → Let's Encrypt
④ 验证方式选"自动验证"(默认),点击申请
⑤ 面板自动逐个验证域名、签发证书、部署到站点
2.2 前提条件(三个都要满足,缺一个就失败)
- 所有域名已正确解析到当前服务器IP(
ping 域名看返回的IP对不对) - 80端口已放行(宝塔面板 → 安全 → 放行80端口;云服务器安全组也要放行)
- 站点根目录存在且有写入权限(Let's Encrypt需要在
.well-known/acme-challenge/目录下写验证文件)
2.3 批量操作避坑
| 问题 | 原因 | 解决 |
|---|---|---|
| 提示"验证超时" | 域名没解析到本机 / 80端口被防火墙挡了 | 检查DNS解析+放行80端口 |
| 添加站点后立即验证HTTPS失败 | DNS解析还没完全生效 | 等5-10分钟再试 |
| 站点超过20个 | 一次性批量太多,面板可能超时 | 分批次操作,每次10个 |
| 某个站点一直失败 | 该站点的nginx配置可能有301重定向,拦截了验证路径 | 见下文"续签失败排查"中的Nginx配置修正 |
三、方案二:Shell脚本批量(50个站点以内)
超过10个站点,面板批量可能超时。用Shell脚本调acme.sh逐个申请和部署,然后配计划任务自动续签。3.1 安装acme.sh
curl https://get.acme.sh | sh -s email=your@email.com
3.2 创建域名列表文件
# 创建 /root/domains.txt,每行一个域名
cat > /root/domains.txt << EOF
example1.com
example2.com
www.example3.com
shop.example4.com
EOF

3.3 批量申请+部署脚本
创建 `/root/batch_ssl.sh`:#!/bin/bash
# 域名列表文件
DOMAIN_FILE="/root/domains.txt"
# 日志文件
LOG_FILE="/var/log/batch_ssl.log"
# 记录开始时间
echo "========== $(date) 开始批量处理 ==========" >> $LOG_FILE
while IFS= read -r domain; do
if [ -z "$domain" ]; then
continue
fi
echo "[$(date '+%H:%M:%S')] 处理: $domain" | tee -a $LOG_FILE
# 用acme.sh签发证书(文件验证方式)
~/.acme.sh/acme.sh --issue -d "$domain" \
-w "/www/wwwroot/$domain" --force 2>&1 | tee -a $LOG_FILE
if [ ${PIPESTATUS[0]} -eq 0 ]; then
echo " ✓ 签发成功: $domain" | tee -a $LOG_FILE
# 部署到宝塔证书目录
CERT_DIR="/www/server/panel/vhost/cert/$domain"
mkdir -p "$CERT_DIR"
~/.acme.sh/acme.sh --install-cert -d "$domain" \
--key-file "$CERT_DIR/privkey.pem" \
--fullchain-file "$CERT_DIR/fullchain.pem" 2>&1 | tee -a $LOG_FILE
echo " ✓ 证书已部署到 $CERT_DIR" | tee -a $LOG_FILE
else
echo " ✗ 签发失败: $domain" | tee -a $LOG_FILE
fi
done < "$DOMAIN_FILE"

# 重载Web服务
/etc/init.d/nginx reload
echo "========== $(date) 全部完成 ==========" >> $LOG_FILE
注意:如果你的站点目录名跟域名不一致,把 /www/wwwroot/$domain 改成实际路径。Apache用户把最后一行改成 /etc/init.d/httpd reload。
3.4 配计划任务自动续签
宝塔面板 → 计划任务 → 添加任务:| 配置项 | 填写内容 |
|---|---|
| 任务类型 | Shell脚本 |
| 任务名称 | 批量续签SSL证书 |
| 执行周期 | 每月1号 凌晨3:00(Let's Encrypt有效期90天,每月跑一次绰绰有余) |
| 脚本内容 | /root/batch_ssl.sh |
/www/server/panel/pyenv/bin/python3 -u /www/server/panel/class/acme_v2.py --renew_v2=1
四、方案三:开源工具批量(100个站点以上)
站点数量破百,Shell脚本逐个串行处理太慢了。两个开源工具推荐:4.1 baota_BT_SSL:宝塔API图形化工具
这是一个Windows桌面程序,通过宝塔API接口直接操作面板,不需要登录面板网页。功能覆盖:
- 批量建站(导入域名列表,自动创建站点)
- 批量申请SSL证书(一次性处理数百个域名)
- 一键部署HTTPS强制跳转
- 批量续签证书
- 文件批处理(批量解压、复制、移动)
① 宝塔面板 → 面板设置 → API接口 → 开启API → 获取App Key
② 把运行工具电脑的公网IP加到白名单
③ 打开BaoTaApi.exe,填入面板地址+App Key → 连接
④ 导入域名列表 → 选择批量申请SSL → 勾选"强制HTTPS" → 执行
GitHub仓库:github.com/xiaocaiji61/baota_BT_SSL,免安装,下载exe直接运行。适合代理商、站群运营、批量运维场景。
4.2 Certd:跨服务器的证书管理平台
如果你的证书分布在多台服务器上,baota_BT_SSL一次只能连一台面板。Certd是一个独立的证书管理平台,通过Docker部署,统一管理所有服务器和所有域名的证书。核心能力:
- 全自动申请证书(支持阿里云、腾讯云、华为云域名)
- 全自动部署证书到多台服务器(宝塔面板、Nginx、CDN等)
- 支持通配符/泛域名证书
- 证书到期前自动续签+自动部署,无需人工干预
- 可视化流水线,拖拽式配置
docker run -d \
--name certd \
-p 7001:7001 \
-v /opt/certd/data:/app/data \
registry.cn-beijing.aliyuncs.com/certd/certd:latest
五、泛域名证书:一个证书覆盖所有子域名
如果你一个主域名下面有大量子域名(www、shop、m、api、admin……),逐个申请太累。一张泛域名证书(*.example.com)可以覆盖所有一级子域名。5.1 关键认知:泛域名只能用DNS验证
HTTP文件验证对泛域名无效。Let's Encrypt的ACME协议强制要求:通配符域名只能走DNS-01挑战(即添加TXT记录验证),不能走HTTP-01。很多人卡在这一步,就是因为没切换验证模式。
5.2 操作步骤
第一步:获取DNS API密钥去你的域名DNS服务商获取API密钥。以最常用的阿里云和腾讯云为例:| DNS服务商 | 获取位置 | 所需权限 |
|---|---|---|
| 阿里云 | RAM访问控制 → 创建子用户 → 获取AccessKey | AliDNS:DescribeDomainRecords + AliDNS:AddDomainRecord |
| 腾讯云DNSPod | DNSPod控制台 → API密钥 → 获取SecretId/SecretKey | QcloudDNSPodFullAccess(或最小权限:CreateRecord + DeleteRecord) |
① 网站 → 对应域名 → 设置 → SSL → Let's Encrypt
② 点击右上角"设置",勾选"使用DNS API验证"(这一步最容易漏!)
③ 选择你的DNS服务商,填入API密钥
④ 域名框填写:*.example.com,example.com(英文逗号分隔,无空格)
⑤ 点击申请
5.3 泛域名格式的三个坑
✓ 正确写法
*.example.com,example.com
必须同时包含泛域名和根域名,因为 *.example.com 不覆盖 example.com 本身
✗ 常见错误
· 只写 *.example.com → 根域名没覆盖
· 写 **.example.com → 不支持多级通配
· 写 *.sub.example.com → 只能单级通配
· 有空格 → *.example.com, example.com
5.4 泛域名证书的续签
DNS模式申请的泛域名证书,自动续签不会默认开启。申请成功后要手动检查:· 计划任务中是否有"续签Let's Encrypt证书"任务,执行周期为每天/每月· 如果没有,手动添加Shell脚本任务:`/www/server/panel/pyenv/bin/python /www/server/panel/class/acme_v2.py --renew`· DNS API密钥一旦变更(如重置了AccessKey),所有已部署的泛域名证书续签会静默失败——面板不报警,证书过期了才知道建议申请完后立刻点一次"续签"按钮,测试整个链路是否通畅。六、自动续签失败的五个排查方向
证书到期前没续上,网站挂了才发现,这种事故太常见了。五个原因逐个排查:修正Nginx配置:80端口验证路径例外
如果你的站点做了全站HTTPS强制跳转,80端口的server块大概率长这样:server {
listen 80;
server_name example.com www.example.com;
# ⚠️ 这一段必须有!
location /.well-known/acme-challenge/ {
root /www/wwwroot/你的站点根目录;
try_files $uri =404;
}
# 其他请求跳转HTTPS
location / {
return 301 https://$host$request_uri;
}
}
七、宝塔9.4.0+的官方自动部署方案
宝塔9.4.0版本开始内置了一个"证书自动部署"功能,适合多台服务器统一管理证书:① 主服务器:SSL → 证书管理 → 上传云端
② 宝塔官网后台:SSL管理 → 创建同步任务 → 生成同步密钥
③ 目标服务器:SSL → 自动部署 → 创建 → 填入密钥 → 选择站点
④ 官网后台:确认接入 → 证书自动同步到所有目标服务器
八、三种方案怎么选
SSL证书这件事,核心问题不是"怎么申请",而是"怎么不忘记续"。Let's Encrypt证书90天有效期,一年要续4次,靠人脑记住是不可能的。不管你站点多少,配好计划任务或自动部署之后,去UptimeRobot之类的免费监控工具加一个SSL到期提醒——到期前30天发邮件,这是最后一道防线。
10个站点以内:面板自带批量+计划任务就够了。10-50个:把上面Shell脚本复制下来,改一下域名列表和站点路径,配好计划任务。50个以上:baota_BT_SSL或Certd二选一,前者适合单台服务器批量操作,后者适合多台服务器统一管理。搞完之后把证书到期监控也配上,以后就不用再操心这件事了。
