多站点批量绑定SSL证书宝塔自动化
为什么要批量绑定SSL证书
手上有几十上百个站点,如果每个都登录宝塔后台手动申请证书,不仅浪费时间,还容易漏掉。
本文介绍一种基于宝塔面板计划任务 + Shell 脚本的自动化方案,针对多个站点统一申请 Let's Encrypt 免费证书并自动部署。
你只需要整理好站点域名列表,剩下的交给脚本定时执行即可。
适用于 LNMP / LAMP 环境,Nginx 或 Apache 通用。
前置准备
在开始之前,请确认以下条件都已满足:
- 宝塔面板版本:建议 7.0 及以上,确保支持 Let's Encrypt API。
- 所有站点域名:必须已经解析到当前服务器 IP,并且 80 端口可正常访问(Let's Encrypt 申请时需验证域名所有权)。
- SSH 终端:需要能登录服务器执行命令,或直接在宝塔面板“文件”管理中操作。
- 系统组件:确保系统已安装
git、curl、openssl,通常默认就有。 - 站点列表文件:创建一个纯文本文件
/root/domains.txt,每行一个域名,例如:
example1.com
example2.cn
demo.org
如果有些站点需要同时支持 www 和根域名,建议先确保两个域名都解析到本机,并在列表里分开写。
分步操作:脚本批量申请并绑定证书
1. 安装 acme.sh(证书申请工具)
登录 SSH,执行以下命令安装 acme.sh:
curl https://get.acme.sh | sh -s email=your@email.com
source ~/.bashrc
your@email.com 换成你自己的邮箱,用于接收证书到期提醒。
2. 编写批量申请脚本
在宝塔面板“文件”中或 SSH 里创建脚本文件 /root/batch_ssl.sh,内容如下:
#!/bin/bash
# 站点域名列表文件
DOMAIN_FILE="/root/domains.txt"
# 证书申请时的临时 webroot 目录(宝塔默认站点根目录)
WEBROOT="/www/wwwroot"
# 读取每一行域名
while IFS= read -r domain; do
if [ -z "$domain" ]; then
continue
fi
echo "正在处理域名: $domain"
# 使用 acme.sh 签发证书,并放入指定目录
~/.acme.sh/acme.sh --issue -d "$domain" -w "$WEBROOT/$domain" --force
if [ $? -eq 0 ]; then
echo "证书申请成功: $domain"
# 部署证书到宝塔站点(使用宝塔API或直接复制证书文件)
# 注意:宝塔面板的证书路径一般是 /www/server/panel/vhost/cert/域名/
# 下面将证书复制到对应目录后需要重启 Nginx/Apache 使生效
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"
echo "证书已部署到 $CERT_DIR"
else
echo "申请失败: $domain"
fi
done < "$DOMAIN_FILE"
# 所有域名处理完后,重载 web 服务
/etc/init.d/nginx reload
echo "所有站点证书处理完成,web服务已重载。"
注意:如果你的站点使用的是 Apache,最后重载服务命令改为 /etc/init.d/httpd reload。
3. 设置脚本执行权限并手动测试
chmod +x /root/batch_ssl.sh
bash /root/batch_ssl.sh
观察输出,成功申请并部署的域名会显示“证书部署完成”,失败的会提示错误。
如果手动运行没问题,再交给计划任务。
4. 添加宝塔计划任务实现自动化
进入宝塔面板 -> 计划任务 -> 添加任务:
- 任务类型:Shell脚本
- 任务名称:批量申请SSL证书
- 执行周期:建议每月或每两月一次(Let's Encrypt 证书有效期90天)。可选择“每月1号 3:00”执行。
- 脚本内容:直接填写
/root/batch_ssl.sh或复制脚本内容进来。 - 提交后,系统会按时执行。
避坑指南
- 域名目录必须存在:脚本中
$WEBROOT/$domain必须对应实际的站点根目录,否则 acme.sh 无法写入验证文件。如果站点根目录名称不是域名,请手动修改脚本。 - 防火墙/安全组放行80端口:Let's Encrypt 验证依赖 80 端口,检查云平台和宝塔面板的防火墙设置。
- 443端口是否已被占用:如果站点已经在使用其他 SSL 证书,可能 443 端口已监听,不影响申请,但要注意证书路径冲突。
- apache 用户权限:如果使用 Apache,可能需要将
privkey.pem的权限设置为www用户可读,否则重启后无法加载。 - 日志留底:建议在脚本中增加重定向输出到日志文件,方便排错(例如
>> /var/log/batch_ssl.log 2>&1)。 - 不要在高峰期执行:批量重启 web 服务可能会造成短暂中断,放在凌晨执行。
效果验证
脚本执行完成后,你可以通过以下方式确认证书是否生效:
- 浏览器访问任意站点,点击地址栏小锁图标,查看证书信息是否匹配域名。
- SSH 检查证书有效期:
openssl x509 -in /www/server/panel/vhost/cert/example.com/fullchain.pem -noout -dates
- 批量检查:写一个简短循环,读取域名列表并检测 HTTPS 响应:
while read domain; do
curl -sI --connect-timeout 5 "https://$domain" | head -n1 | grep -q "200" && echo "$domain OK" || echo "$domain FAIL"
done < /root/domains.txt
如果所有域名均返回 OK,说明批量绑定 SSL 成功。
常见问题
Q:申请证书时提示“未验证域名所有权”,怎么办?
A:检查域名是否解析到本机、80端口是否被屏蔽、站点根目录是否可写。也可以尝试先用宝塔面板手动申请一个测试。
Q:证书申请成功但部署后站点没生效?
A:检查 web 服务是否重载成功,或者查看 /www/server/panel/vhost/cert/域名/ 下有无证书文件。有时需要手动在宝塔站点设置中重新选择证书再保存一次。
Q:如何取消某个域名不再自动申请?
A:从 /root/domains.txt 中移除该域名,并删除对应的证书目录。
---
如果你正在管理大量站点,建议先按本文步骤在测试环境跑通,再投入正式使用。
遇到异常时优先回看避坑和高频问题部分,大部分错误都可以通过调整权限或域名列表解决。