在 CentOS 服务器上自动申请和更新多域名 SSL 证书
本文将介绍如何使用 Shell 脚本自动化管理多个域名的 SSL 证书,包括申请、安装和自动更新。
背景
在运维工作中,经常需要为多个域名申请和更新 SSL 证书。手动操作不

仅繁琐,还容易出错。通过脚本自动化这个过程,可以大大提高工作效率。
实现方案
我们使用 Let's Encrypt 提供的免费证书服务,结合 certbot 工具来实现证书的申请和更新。脚本支持同时处理多个域名,并设置自动更新任务。
1. 完整脚本
#!/bin/bash
# 基础配置
EMAIL="your-email@example.com" # 替换为您的邮箱
CERT_PATH="/etc/nginx/cert" # nginx证书固定目录
WEBROOT_PATH="/usr/share/nginx/html" # nginx默认网站目录
LOG_FILE="/var/log/cert-renewal.log"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# 检查参数
if [ $# -eq 0 ]; then
echo "使用方法: $0 domain1.com [domain2.com ...]"
echo "示例: $0 api2.example.comapi.example.com"
exit 1
fi
# 检查是否以 root 权限运行
if [ "$EUID" -ne 0 ]; then
log "请使用 root 权限运行此脚本"
exit 1
fi
# 确保目录存在
mkdir -p $CERT_PATH
mkdir -p $WEBROOT_PATH
# 安装必要的软件包
log "检查并安装必要的软件包..."
yum install -y epel-release
yum install -y certbot python3-certbot-nginx
# 处理每个域名
for DOMAIN in "$@"; do
log "开始处理域名: $DOMAIN"
# 申请证书
log "开始申请 Let's Encrypt 证书..."
certbot certonly --webroot \
--webroot-path $WEBROOT_PATH \
--agree-tos \
--email $EMAIL \
-d $DOMAIN
# 检查证书是否申请成功
if [ $? -eq 0 ]; then
log "证书申请成功: $DOMAIN"
# 复制证书到nginx证书目录
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem $CERT_PATH/$DOMAIN.pem
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem $CERT_PATH/$DOMAIN.key
# 设置正确的权限
chown -R nginx:nginx $CERT_PATH
chmod 600 $CERT_PATH/$DOMAIN.key
chmod 644 $CERT_PATH/$DOMAIN.pem
log "证书已复制到Nginx目录:$CERT_PATH/$DOMAIN.pem"
else
log "证书申请失败: $DOMAIN"
continue
fi
done
# 创建统一的证书更新脚本
cat > /usr/local/bin/renew-cert.sh << 'EOF'
#!/bin/bash
CERT_PATH="/etc/nginx/cert"
WEBROOT_PATH="/usr/share/nginx/html"
# 更新所有证书
certbot renew --webroot --webroot-path $WEBROOT_PATH --quiet
# 更新成功后,复制所有证书到nginx目录
for CERT_DIR in /etc/letsencrypt/live/*; do
if [ -d "$CERT_DIR" ]; then
DOMAIN=$(basename "$CERT_DIR")
cp "$CERT_DIR/fullchain.pem" "$CERT_PATH/$DOMAIN.pem"
cp "$CERT_DIR/privkey.pem" "$CERT_PATH/$DOMAIN.key"
chown nginx:nginx "$CERT_PATH/$DOMAIN.pem" "$CERT_PATH/$DOMAIN.key"
chmod 600 "$CERT_PATH/$DOMAIN.key"
chmod 644 "$CERT_PATH/$DOMAIN.pem"
fi
done
# 重新加载nginx配置
nginx -s reload
EOF
# 设置更新脚本权限
chmod +x /usr/local/bin/renew-cert.sh
# 添加定时任务
(crontab -l 2>/dev/null | grep -v renew-cert.sh; echo "0 2 1 * * /usr/local/bin/renew-cert.sh") | crontab -
log "证书自动更新任务已设置"
log "所有证书位于: $CERT_PATH/"
log "下次更新时间: 下月1号凌晨2点"
# 重新加载nginx配置
nginx -s reload
2. 主要功能
- 支持同时处理多个域名的证书申请
- 自动安装必要的软件包
- 统一管理证书存储位置
- 自动设置证书更新任务
- 详细的操作日志记录
- 适当的错误处理机制
3. 使用方法
# 处理单个域名
./ssl-cert.sh domain.com
# 处理多个域名
./ssl-cert.sh domain1.com domain2.com domain3.com

常见问题及解决方案
1. 换行符问题
https.sh: line 2: #39;\r': command not found
这是因为脚本在 Windows 系统编辑后传到 Linux 服务器导致的换行符问题。
解决方法:
# 方法一:安装并使用 dos2unix
yum install -y dos2unix
dos2unix ssl-cert.sh
# 方法二:使用 sed 命令
sed -i 's/\r//' ssl-cert.sh
2. 证书验证失败
错误信息:
Challenge failed for domain domain.com
Type: unauthorized
Detail: Invalid response from http://domain.com/.well-known/acme-challenge/
解决步骤:
- 配置 Nginx
server {
listen 80;
server_name domain.com;
# 添加证书验证路径
location /.well-known/acme-challenge/ {
root /usr/share/nginx/html;
}
}
- 检查目录权限
mkdir -p /usr/share/nginx/html/.well-known/acme-challenge
chown -R nginx:nginx /usr/share/nginx/html
chmod -R 755 /usr/share/nginx/html
- 验证配置
# 测试 nginx 配置
nginx -t
nginx -s reload
# 测试验证路径
echo "test" > /usr/share/nginx/html/.well-known/acme-challenge/test.txt
curl http://domain.com/.well-known/acme-challenge/test.txt
3. 防火墙设置
确保服务器的 80 端口对外开放:
firewall-cmd --permanent --add-service=http
firewall-cmd --reload
注意事项
- 运行脚本前确保域名已正确解析到服务器
- 确保服务器的 80 端口可以正常访问
- 证书文件统一存放在 /etc/nginx/cert 目录下
- 自动更新任务默认在每月 1 号凌晨 2 点执行
维护建议
- 定期检查证书状态
certbot certificates
- 检查自动更新任务
crontab -l | grep renew-cert
- 查看更新日志
tail -f /var/log/cert-renewal.log
总结
通过这个自动化脚本,我们可以轻松管理多个域名的 SSL 证书,大大减少了手动操作的工作量和出错风险。脚本的模块化设计也使得维护和故障排查变得更加容易。
对于那些管理多个网站和域名的运维人员来说,这个脚本可以显著提高工作效率。通过及时处理常见错误,我们可以确保证书申请和更新过程的顺利进行。
希望这个工具和相关经验分享对大家有所帮助。如果有任何问题或建议,欢迎在评论区讨论。